Updating vendors.

1.9.x
Julio Montoya 12 years ago
parent b2dda01962
commit 48d1fab5b9
  1. 2
      vendor/autoload.php
  2. 186
      vendor/composer/ClassLoader.php
  3. 11
      vendor/composer/autoload_real.php
  4. 360
      vendor/composer/installed.json
  5. 17
      vendor/doctrine/cache/.travis.yml
  6. 7
      vendor/doctrine/cache/README.md
  7. 4
      vendor/doctrine/cache/composer.json
  8. 7
      vendor/doctrine/cache/lib/Doctrine/Common/Cache/ApcCache.php
  9. 1
      vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php
  10. 2
      vendor/doctrine/cache/lib/Doctrine/Common/Cache/FilesystemCache.php
  11. 2
      vendor/doctrine/cache/lib/Doctrine/Common/Cache/PhpFileCache.php
  12. 3
      vendor/doctrine/cache/lib/Doctrine/Common/Cache/RedisCache.php
  13. 10
      vendor/doctrine/cache/lib/Doctrine/Common/Cache/RiakCache.php
  14. 17
      vendor/monolog/monolog/CHANGELOG.mdown
  15. 22
      vendor/monolog/monolog/README.mdown
  16. 11
      vendor/monolog/monolog/composer.json
  17. 6
      vendor/monolog/monolog/doc/usage.md
  18. 19
      vendor/monolog/monolog/src/Monolog/ErrorHandler.php
  19. 7
      vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php
  20. 6
      vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php
  21. 66
      vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php
  22. 20
      vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php
  23. 2
      vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php
  24. 6
      vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php
  25. 2
      vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php
  26. 23
      vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php
  27. 6
      vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php
  28. 66
      vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php
  29. 4
      vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php
  30. 7
      vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php
  31. 43
      vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php
  32. 10
      vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php
  33. 4
      vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php
  34. 2
      vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php
  35. 39
      vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php
  36. 13
      vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php
  37. 64
      vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php
  38. 5
      vendor/monolog/monolog/src/Monolog/Logger.php
  39. 14
      vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php
  40. 11
      vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php
  41. 4
      vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php
  42. 31
      vendor/monolog/monolog/tests/Monolog/ErrorHandlerTest.php
  43. 158
      vendor/monolog/monolog/tests/Monolog/Formatter/ChromePHPFormatterTest.php
  44. 158
      vendor/monolog/monolog/tests/Monolog/Formatter/GelfMessageFormatterTest.php
  45. 41
      vendor/monolog/monolog/tests/Monolog/Formatter/JsonFormatterTest.php
  46. 164
      vendor/monolog/monolog/tests/Monolog/Formatter/LineFormatterTest.php
  47. 160
      vendor/monolog/monolog/tests/Monolog/Formatter/LogstashFormatterTest.php
  48. 182
      vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php
  49. 111
      vendor/monolog/monolog/tests/Monolog/Formatter/WildfireFormatterTest.php
  50. 32
      vendor/monolog/monolog/tests/Monolog/Functional/Handler/FirePHPHandlerTest.php
  51. 104
      vendor/monolog/monolog/tests/Monolog/Handler/AbstractHandlerTest.php
  52. 79
      vendor/monolog/monolog/tests/Monolog/Handler/AbstractProcessingHandlerTest.php
  53. 38
      vendor/monolog/monolog/tests/Monolog/Handler/AmqpExchangeMock.php
  54. 74
      vendor/monolog/monolog/tests/Monolog/Handler/AmqpHandlerTest.php
  55. 149
      vendor/monolog/monolog/tests/Monolog/Handler/BufferHandlerTest.php
  56. 139
      vendor/monolog/monolog/tests/Monolog/Handler/ChromePHPHandlerTest.php
  57. 41
      vendor/monolog/monolog/tests/Monolog/Handler/CouchDBHandlerTest.php
  58. 52
      vendor/monolog/monolog/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php
  59. 189
      vendor/monolog/monolog/tests/Monolog/Handler/FingersCrossedHandlerTest.php
  60. 94
      vendor/monolog/monolog/tests/Monolog/Handler/FirePHPHandlerTest.php
  61. 0
      vendor/monolog/monolog/tests/Monolog/Handler/Fixtures/.gitkeep
  62. 94
      vendor/monolog/monolog/tests/Monolog/Handler/GelfHandlerTest.php
  63. 25
      vendor/monolog/monolog/tests/Monolog/Handler/GelfMocks.php
  64. 89
      vendor/monolog/monolog/tests/Monolog/Handler/GroupHandlerTest.php
  65. 110
      vendor/monolog/monolog/tests/Monolog/Handler/HipChatHandlerTest.php
  66. 75
      vendor/monolog/monolog/tests/Monolog/Handler/MailHandlerTest.php
  67. 26
      vendor/monolog/monolog/tests/Monolog/Handler/MockRavenClient.php
  68. 63
      vendor/monolog/monolog/tests/Monolog/Handler/MongoDBHandlerTest.php
  69. 43
      vendor/monolog/monolog/tests/Monolog/Handler/NativeMailerHandlerTest.php
  70. 65
      vendor/monolog/monolog/tests/Monolog/Handler/NewRelicHandlerTest.php
  71. 33
      vendor/monolog/monolog/tests/Monolog/Handler/NullHandlerTest.php
  72. 142
      vendor/monolog/monolog/tests/Monolog/Handler/PushoverHandlerTest.php
  73. 135
      vendor/monolog/monolog/tests/Monolog/Handler/RavenHandlerTest.php
  74. 71
      vendor/monolog/monolog/tests/Monolog/Handler/RedisHandlerTest.php
  75. 99
      vendor/monolog/monolog/tests/Monolog/Handler/RotatingFileHandlerTest.php
  76. 283
      vendor/monolog/monolog/tests/Monolog/Handler/SocketHandlerTest.php
  77. 88
      vendor/monolog/monolog/tests/Monolog/Handler/StreamHandlerTest.php
  78. 43
      vendor/monolog/monolog/tests/Monolog/Handler/SyslogHandlerTest.php
  79. 56
      vendor/monolog/monolog/tests/Monolog/Handler/TestHandlerTest.php
  80. 69
      vendor/monolog/monolog/tests/Monolog/Handler/ZendMonitorHandlerTest.php
  81. 409
      vendor/monolog/monolog/tests/Monolog/LoggerTest.php
  82. 65
      vendor/monolog/monolog/tests/Monolog/Processor/IntrospectionProcessorTest.php
  83. 29
      vendor/monolog/monolog/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php
  84. 29
      vendor/monolog/monolog/tests/Monolog/Processor/MemoryUsageProcessorTest.php
  85. 30
      vendor/monolog/monolog/tests/Monolog/Processor/ProcessIdProcessorTest.php
  86. 27
      vendor/monolog/monolog/tests/Monolog/Processor/UidProcessorTest.php
  87. 68
      vendor/monolog/monolog/tests/Monolog/Processor/WebProcessorTest.php
  88. 47
      vendor/monolog/monolog/tests/Monolog/PsrLogCompatTest.php
  89. 58
      vendor/monolog/monolog/tests/Monolog/TestCase.php
  90. 13
      vendor/monolog/monolog/tests/bootstrap.php
  91. 5
      vendor/symfony/process/Symfony/Component/Process/CHANGELOG.md
  92. 7
      vendor/symfony/process/Symfony/Component/Process/PhpExecutableFinder.php
  93. 386
      vendor/symfony/process/Symfony/Component/Process/Process.php
  94. 35
      vendor/symfony/process/Symfony/Component/Process/ProcessBuilder.php
  95. 2
      vendor/symfony/process/Symfony/Component/Process/ProcessUtils.php
  96. 2
      vendor/symfony/process/Symfony/Component/Process/README.md
  97. 142
      vendor/symfony/process/Symfony/Component/Process/Tests/AbstractProcessTest.php
  98. 8
      vendor/symfony/process/Symfony/Component/Process/Tests/PhpExecutableFinderTest.php
  99. 104
      vendor/symfony/process/Symfony/Component/Process/Tests/ProcessBuilderTest.php
  100. 63
      vendor/symfony/process/Symfony/Component/Process/Tests/ProcessTestHelper.php
  101. Some files were not shown because too many files have changed in this diff Show More

@ -4,4 +4,4 @@
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInit0bd80a5dd87aafa19d62e78424e580b4::getLoader();
return ComposerAutoloaderInit66dd73b468c5607bacc52774d2bd8959::getLoader();

@ -42,19 +42,36 @@ namespace Composer\Autoload;
*/
class ClassLoader
{
private $prefixes = array();
private $fallbackDirs = array();
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
public function getPrefixes()
{
return call_user_func_array('array_merge', $this->prefixes);
return call_user_func_array('array_merge', $this->prefixesPsr0);
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirs;
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
@ -75,23 +92,24 @@ class ClassLoader
}
/**
* Registers a set of classes, merging with any others previously set.
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The classes prefix
* @param array|string $paths The location(s) of the classes
* @param bool $prepend Prepend the location(s)
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirs = array_merge(
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirs
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirs = array_merge(
$this->fallbackDirs,
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
@ -100,38 +118,104 @@ class ClassLoader
}
$first = $prefix[0];
if (!isset($this->prefixes[$first][$prefix])) {
$this->prefixes[$first][$prefix] = (array) $paths;
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixes[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-0 base directories
* @param bool $prepend Whether to prepend the directories
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixes[$first][$prefix]
$this->prefixDirsPsr4[$prefix]
);
} else {
$this->prefixes[$first][$prefix] = array_merge(
$this->prefixes[$first][$prefix],
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of classes, replacing any others previously set.
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The classes prefix
* @param array|string $paths The location(s) of the classes
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirs = (array) $paths;
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
return;
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
*/
public function setPsr4($prefix, $paths) {
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
$this->prefixes[substr($prefix, 0, 1)][$prefix] = (array) $paths;
}
/**
@ -202,45 +286,69 @@ class ClassLoader
$class = substr($class, 1);
}
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php';
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) {
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$classPath = strtr(substr($class, 0, $pos), '\\', DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
$className = substr($class, $pos + 1);
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$classPath = null;
$className = $class;
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . '.php';
}
$classPath .= strtr($className, '_', DIRECTORY_SEPARATOR) . '.php';
$first = $class[0];
if (isset($this->prefixes[$first])) {
foreach ($this->prefixes[$first] as $prefix => $dirs) {
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
return $dir . DIRECTORY_SEPARATOR . $classPath;
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
foreach ($this->fallbackDirs as $dir) {
if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
return $dir . DIRECTORY_SEPARATOR . $classPath;
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) {
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
// Remember that this class does not exist.
return $this->classMap[$class] = false;
}
}

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit0bd80a5dd87aafa19d62e78424e580b4
class ComposerAutoloaderInit66dd73b468c5607bacc52774d2bd8959
{
private static $loader;
@ -19,9 +19,9 @@ class ComposerAutoloaderInit0bd80a5dd87aafa19d62e78424e580b4
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit0bd80a5dd87aafa19d62e78424e580b4', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInit66dd73b468c5607bacc52774d2bd8959', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit0bd80a5dd87aafa19d62e78424e580b4', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInit66dd73b468c5607bacc52774d2bd8959', 'loadClassLoader'));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
@ -31,6 +31,11 @@ class ComposerAutoloaderInit0bd80a5dd87aafa19d62e78424e580b4
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);

@ -41,19 +41,149 @@
"event-dispatcher"
]
},
{
"name": "alchemy/binary-driver",
"version": "1.5.0",
"version_normalized": "1.5.0.0",
"source": {
"type": "git",
"url": "https://github.com/alchemy-fr/BinaryDriver.git",
"reference": "b32c03d4b56ce29f783051eac55887adae654b41"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/BinaryDriver/zipball/b32c03d4b56ce29f783051eac55887adae654b41",
"reference": "b32c03d4b56ce29f783051eac55887adae654b41",
"shasum": ""
},
"require": {
"evenement/evenement": "~1.0",
"monolog/monolog": "~1.3",
"php": ">=5.3.3",
"psr/log": "~1.0",
"symfony/process": "~2.0"
},
"require-dev": {
"phpunit/phpunit": "~3.7"
},
"time": "2013-06-21 15:51:20",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Alchemy": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Romain Neutron",
"email": "imprec@gmail.com",
"homepage": "http://www.lickmychip.com/"
},
{
"name": "Nicolas Le Goff",
"email": "legoff.n@gmail.com"
},
{
"name": "Phraseanet Team",
"email": "info@alchemy.fr",
"homepage": "http://www.phraseanet.com/"
}
],
"description": "A set of tools to build binary drivers",
"keywords": [
"binary",
"driver"
]
},
{
"name": "php-ffmpeg/php-ffmpeg",
"version": "0.3.x-dev",
"version_normalized": "0.3.9999999.9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/alchemy-fr/PHP-FFmpeg.git",
"reference": "185fb5c33da594db7ffbf3f89d48e9841bc666a0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/PHP-FFmpeg/zipball/185fb5c33da594db7ffbf3f89d48e9841bc666a0",
"reference": "185fb5c33da594db7ffbf3f89d48e9841bc666a0",
"shasum": ""
},
"require": {
"alchemy/binary-driver": "~1.5",
"doctrine/cache": "~1.0",
"evenement/evenement": "~1.0",
"neutron/temporary-filesystem": "~2.1, >=2.1.1",
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~3.7",
"sami/sami": "~1.0",
"silex/silex": "~1.0"
},
"suggest": {
"php-ffmpeg/extras": "A compilation of common audio & video drivers for PHP-FFMpeg"
},
"time": "2013-10-21 12:13:46",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.4-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-0": {
"FFMpeg": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Romain Neutron",
"email": "imprec@gmail.com",
"homepage": "http://www.lickmychip.com/"
},
{
"name": "Phraseanet Team",
"email": "info@alchemy.fr",
"homepage": "http://www.phraseanet.com/"
}
],
"description": "FFMpeg PHP, an Object Oriented library to communicate with AVconv / ffmpeg",
"keywords": [
"audio",
"audio processing",
"avconv",
"avprobe",
"ffmpeg",
"ffprobe",
"video",
"video processing"
]
},
{
"name": "doctrine/cache",
"version": "v1.1",
"version_normalized": "1.1.0.0",
"version": "v1.3.0",
"version_normalized": "1.3.0.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "2c9761ff1d13e188d5f7378066c1ce2882d7a336"
"reference": "e16d7adf45664a50fa86f515b6d5e7f670130449"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/2c9761ff1d13e188d5f7378066c1ce2882d7a336",
"reference": "2c9761ff1d13e188d5f7378066c1ce2882d7a336",
"url": "https://api.github.com/repos/doctrine/cache/zipball/e16d7adf45664a50fa86f515b6d5e7f670130449",
"reference": "e16d7adf45664a50fa86f515b6d5e7f670130449",
"shasum": ""
},
"require": {
@ -62,7 +192,11 @@
"conflict": {
"doctrine/common": ">2.2,<2.4"
},
"time": "2013-08-07 16:04:25",
"require-dev": {
"phpunit/phpunit": ">=3.7",
"satooshi/php-coveralls": "~0.6"
},
"time": "2013-10-25 19:04:14",
"type": "library",
"extra": {
"branch-alias": {
@ -83,7 +217,8 @@
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com",
"homepage": "http://www.jwage.com/"
"homepage": "http://www.jwage.com/",
"role": "Creator"
},
{
"name": "Guilherme Blanco",
@ -152,68 +287,19 @@
"psr-3"
]
},
{
"name": "symfony/process",
"version": "v2.3.4",
"version_normalized": "2.3.4.0",
"target-dir": "Symfony/Component/Process",
"source": {
"type": "git",
"url": "https://github.com/symfony/Process.git",
"reference": "1e91553e1cedd0b8fb1da6ea4f89b02e21713d5b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Process/zipball/1e91553e1cedd0b8fb1da6ea4f89b02e21713d5b",
"reference": "1e91553e1cedd0b8fb1da6ea4f89b02e21713d5b",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"time": "2013-08-22 06:42:25",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Symfony\\Component\\Process\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony Process Component",
"homepage": "http://symfony.com"
},
{
"name": "monolog/monolog",
"version": "1.6.0",
"version_normalized": "1.6.0.0",
"version": "1.7.0",
"version_normalized": "1.7.0.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "f72392d0e6eb855118f5a84e89ac2d257c704abd"
"reference": "6225b22de9dcf36546be3a0b2fa8e3d986153f57"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/f72392d0e6eb855118f5a84e89ac2d257c704abd",
"reference": "f72392d0e6eb855118f5a84e89ac2d257c704abd",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/6225b22de9dcf36546be3a0b2fa8e3d986153f57",
"reference": "6225b22de9dcf36546be3a0b2fa8e3d986153f57",
"shasum": ""
},
"require": {
@ -221,22 +307,27 @@
"psr/log": "~1.0"
},
"require-dev": {
"aws/aws-sdk-php": "~2.4.8",
"doctrine/couchdb": "dev-master",
"mlehner/gelf-php": "1.0.*",
"raven/raven": "0.5.*"
"phpunit/phpunit": "~3.7.0",
"raven/raven": "0.5.*",
"ruflin/elastica": "0.90.*"
},
"suggest": {
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
"ext-mongo": "Allow sending log messages to a MongoDB server",
"mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server",
"raven/raven": "Allow sending log messages to a Sentry server"
"raven/raven": "Allow sending log messages to a Sentry server",
"ruflin/elastica": "Allow sending log messages to an Elastic Search server"
},
"time": "2013-07-28 22:38:30",
"time": "2013-11-14 19:48:31",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
"dev-master": "1.7.x-dev"
}
},
"installation-source": "dist",
@ -266,36 +357,35 @@
]
},
{
"name": "alchemy/binary-driver",
"version": "1.5.0",
"version_normalized": "1.5.0.0",
"name": "symfony/process",
"version": "v2.4.1",
"version_normalized": "2.4.1.0",
"target-dir": "Symfony/Component/Process",
"source": {
"type": "git",
"url": "https://github.com/alchemy-fr/BinaryDriver.git",
"reference": "b32c03d4b56ce29f783051eac55887adae654b41"
"url": "https://github.com/symfony/Process.git",
"reference": "58fdccb311e44f28866f976c2d7b3227e9f713db"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/BinaryDriver/zipball/b32c03d4b56ce29f783051eac55887adae654b41",
"reference": "b32c03d4b56ce29f783051eac55887adae654b41",
"url": "https://api.github.com/repos/symfony/Process/zipball/58fdccb311e44f28866f976c2d7b3227e9f713db",
"reference": "58fdccb311e44f28866f976c2d7b3227e9f713db",
"shasum": ""
},
"require": {
"evenement/evenement": "~1.0",
"monolog/monolog": "~1.3",
"php": ">=5.3.3",
"psr/log": "~1.0",
"symfony/process": "~2.0"
},
"require-dev": {
"phpunit/phpunit": "~3.7"
"php": ">=5.3.3"
},
"time": "2013-06-21 15:51:20",
"time": "2014-01-05 02:10:50",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.4-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Alchemy": "src"
"Symfony\\Component\\Process\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
@ -304,50 +394,41 @@
],
"authors": [
{
"name": "Romain Neutron",
"email": "imprec@gmail.com",
"homepage": "http://www.lickmychip.com/"
},
{
"name": "Nicolas Le Goff",
"email": "legoff.n@gmail.com"
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Phraseanet Team",
"email": "info@alchemy.fr",
"homepage": "http://www.phraseanet.com/"
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "A set of tools to build binary drivers",
"keywords": [
"binary",
"driver"
]
"description": "Symfony Process Component",
"homepage": "http://symfony.com"
},
{
"name": "symfony/filesystem",
"version": "v2.3.7",
"version_normalized": "2.3.7.0",
"version": "v2.4.1",
"version_normalized": "2.4.1.0",
"target-dir": "Symfony/Component/Filesystem",
"source": {
"type": "git",
"url": "https://github.com/symfony/Filesystem.git",
"reference": "2b8995042086c5552c94d33b5553c492e9cfc00e"
"reference": "b3c3b5a8108b3e5d604dc23241b4ea84a067fc78"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Filesystem/zipball/2b8995042086c5552c94d33b5553c492e9cfc00e",
"reference": "2b8995042086c5552c94d33b5553c492e9cfc00e",
"url": "https://api.github.com/repos/symfony/Filesystem/zipball/b3c3b5a8108b3e5d604dc23241b4ea84a067fc78",
"reference": "b3c3b5a8108b3e5d604dc23241b4ea84a067fc78",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"time": "2013-09-19 09:45:20",
"time": "2013-12-31 13:43:26",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3-dev"
"dev-master": "2.4-dev"
}
},
"installation-source": "dist",
@ -414,76 +495,5 @@
}
],
"description": "Symfony filesystem extension to handle temporary files"
},
{
"name": "php-ffmpeg/php-ffmpeg",
"version": "0.3.x-dev",
"version_normalized": "0.3.9999999.9999999-dev",
"source": {
"type": "git",
"url": "https://github.com/alchemy-fr/PHP-FFmpeg.git",
"reference": "185fb5c33da594db7ffbf3f89d48e9841bc666a0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/PHP-FFmpeg/zipball/185fb5c33da594db7ffbf3f89d48e9841bc666a0",
"reference": "185fb5c33da594db7ffbf3f89d48e9841bc666a0",
"shasum": ""
},
"require": {
"alchemy/binary-driver": "~1.5",
"doctrine/cache": "~1.0",
"evenement/evenement": "~1.0",
"neutron/temporary-filesystem": "~2.1, >=2.1.1",
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~3.7",
"sami/sami": "~1.0",
"silex/silex": "~1.0"
},
"suggest": {
"php-ffmpeg/extras": "A compilation of common audio & video drivers for PHP-FFMpeg"
},
"time": "2013-10-21 12:13:46",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.4-dev"
}
},
"installation-source": "source",
"autoload": {
"psr-0": {
"FFMpeg": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Romain Neutron",
"email": "imprec@gmail.com",
"homepage": "http://www.lickmychip.com/"
},
{
"name": "Phraseanet Team",
"email": "info@alchemy.fr",
"homepage": "http://www.phraseanet.com/"
}
],
"description": "FFMpeg PHP, an Object Oriented library to communicate with AVconv / ffmpeg",
"keywords": [
"audio",
"audio processing",
"avconv",
"avprobe",
"ffmpeg",
"ffprobe",
"video",
"video processing"
]
}
]

@ -5,5 +5,22 @@ php:
- 5.4
- 5.5
services:
- riak
- mongodb
- memcached
- redis-server
before_script:
- pecl install redis
- pecl install riak-beta
- sh -c "if [ `php-config --vernum` -ge 50500 ] ; then pecl config-set preferred_state beta; printf "yes\n" | pecl install apcu ; else echo 'extension="apc.so"' >> ./tests/travis/php.ini ;fi"
- composer self-update
- composer --prefer-source --dev install
- phpenv config-add ./tests/travis/php.ini
script:
- ./vendor/bin/phpunit -c ./tests/travis/phpunit.travis.xml -v
after_script:
- php vendor/bin/coveralls -v

@ -1,9 +1,14 @@
# Doctrine Cache
Master: [![Build Status](https://secure.travis-ci.org/doctrine/cache.png?branch=master)](http://travis-ci.org/doctrine/cache) [![Coverage Status](https://coveralls.io/repos/doctrine/cache/badge.png?branch=master)](https://coveralls.io/r/doctrine/cache?branch=master)
[![Latest Stable Version](https://poser.pugx.org/doctrine/cache/v/stable.png)](https://packagist.org/packages/doctrine/cache) [![Total Downloads](https://poser.pugx.org/doctrine/cache/downloads.png)](https://packagist.org/packages/doctrine/cache)
Cache component extracted from the Doctrine Common project.
## Changelog
### v1.1
### v1.2
* Added support for MongoDB as Cache Provider
* Fix namespace version reset

@ -15,6 +15,10 @@
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": ">=3.7",
"satooshi/php-coveralls": "~0.6"
},
"conflict": {
"doctrine/common": ">2.2,<2.4"
},

@ -80,6 +80,13 @@ class ApcCache extends CacheProvider
$info = apc_cache_info();
$sma = apc_sma_info();
// @TODO - Temporary fix @see https://github.com/krakjoe/apcu/pull/42
if (PHP_VERSION_ID >= 50500) {
$info['num_hits'] = isset($info['num_hits']) ? $info['num_hits'] : $info['nhits'];
$info['num_misses'] = isset($info['num_misses']) ? $info['num_misses'] : $info['nmisses'];
$info['start_time'] = isset($info['start_time']) ? $info['start_time'] : $info['stime'];
}
return array(
Cache::STATS_HITS => $info['num_hits'],
Cache::STATS_MISSES => $info['num_misses'],

@ -57,6 +57,7 @@ abstract class CacheProvider implements Cache
public function setNamespace($namespace)
{
$this->namespace = (string) $namespace;
$this->namespaceVersion = null;
}
/**

@ -108,6 +108,6 @@ class FilesystemCache extends FileCache
mkdir($filepath, 0777, true);
}
return file_put_contents($filename, $lifeTime . PHP_EOL . $data);
return file_put_contents($filename, $lifeTime . PHP_EOL . $data) !== false;
}
}

@ -102,6 +102,6 @@ class PhpFileCache extends FileCache
$value = var_export($value, true);
$code = sprintf('<?php return %s;', $value);
return file_put_contents($filename, $code);
return file_put_contents($filename, $code) !== false;
}
}

@ -82,6 +82,7 @@ class RedisCache extends CacheProvider
if ($lifeTime > 0) {
return $this->redis->setex($id, $lifeTime, $data);
}
return $this->redis->set($id, $data);
}
@ -90,7 +91,7 @@ class RedisCache extends CacheProvider
*/
protected function doDelete($id)
{
return $this->redis->delete($id);
return $this->redis->delete($id) > 0;
}
/**

@ -57,7 +57,7 @@ class RiakCache extends CacheProvider
protected function doFetch($id)
{
try {
$response = $this->bucket->get(urlencode($id));
$response = $this->bucket->get($id);
// No objects found
if ( ! $response->hasObject()) {
@ -99,7 +99,7 @@ class RiakCache extends CacheProvider
$input->setReturnHead(true);
$response = $this->bucket->get(urlencode($id), $input);
$response = $this->bucket->get($id, $input);
// No objects found
if ( ! $response->hasObject()) {
@ -129,7 +129,7 @@ class RiakCache extends CacheProvider
protected function doSave($id, $data, $lifeTime = 0)
{
try {
$object = new Object(urlencode($id));
$object = new Object($id);
$object->setContent(serialize($data));
@ -153,7 +153,7 @@ class RiakCache extends CacheProvider
protected function doDelete($id)
{
try {
$this->bucket->delete(urlencode($id));
$this->bucket->delete($id);
return true;
} catch (Exception\BadArgumentsException $e) {
@ -240,7 +240,7 @@ class RiakCache extends CacheProvider
$putInput = new Input\PutInput();
$putInput->setVClock($vClock);
$mergedObject = new Object(urlencode($id));
$mergedObject = new Object($id);
$mergedObject->setContent($winner->getContent());
$this->bucket->put($mergedObject, $putInput);

@ -1,3 +1,20 @@
### 1.7.0 (2013-11-14)
* Added ElasticSearchHandler to send logs to an Elastic Search server
* Added DynamoDbHandler and ScalarFormatter to send logs to Amazon's Dynamo DB
* Added SyslogUdpHandler to send logs to a remote syslogd server
* Added LogglyHandler to send logs to a Loggly account
* Added $level to IntrospectionProcessor so it only adds backtraces when needed
* Added $version to LogstashFormatter to allow using the new v1 Logstash format
* Added $appName to NewRelicHandler
* Added configuration of Pushover notification retries/expiry
* Added $maxColumnWidth to NativeMailerHandler to change the 70 chars default
* Added chainability to most setters for all handlers
* Fixed RavenHandler batch processing so it takes the message from the record with highest priority
* Fixed HipChatHandler batch processing so it sends all messages at once
* Fixed issues with eAccelerator
* Fixed and improved many small things
### 1.6.0 (2013-07-29)
* Added HipChatHandler to send logs to a HipChat chat room

@ -45,8 +45,8 @@ the bottom of the stack that will log anything to disk, and on top of that add
a `MailHandler` that will send emails only when an error message is logged.
Handlers also have a `$bubble` property which defines whether they block the
record or not if they handled it. In this example, setting the `MailHandler`'s
`$bubble` argument to true means that all records will propagate to the
`StreamHandler`, even the errors that are handled by the `MailHandler`.
`$bubble` argument to false means that records handled by the `MailHandler` will
not propagate to the `StreamHandler` anymore.
You can create many `Logger`s, each defining a channel (e.g.: db, request,
router, ..) and each of them combining various handlers, which can be shared
@ -68,16 +68,13 @@ information (tags, user ip, ..) to the records before they are handled.
Log Levels
----------
Monolog supports all 8 logging levels defined in
[RFC 5424](http://tools.ietf.org/html/rfc5424), but unless you specifically
need syslog compatibility, it is advised to only use DEBUG, INFO, WARNING,
ERROR, CRITICAL, ALERT.
Monolog supports the logging levels described by [RFC 5424](http://tools.ietf.org/html/rfc5424).
- **DEBUG** (100): Detailed debug information.
- **INFO** (200): Interesting events. Examples: User logs in, SQL logs.
- NOTICE (250): Normal but significant events.
- **NOTICE** (250): Normal but significant events.
- **WARNING** (300): Exceptional occurrences that are not errors. Examples:
Use of deprecated APIs, poor use of an API, undesirable things that are not
@ -93,7 +90,7 @@ ERROR, CRITICAL, ALERT.
down, database unavailable, etc. This should trigger the SMS alerts and wake
you up.
- EMERGENCY (600): Emergency: system is unusable.
- **EMERGENCY** (600): Emergency: system is unusable.
Docs
====
@ -135,6 +132,8 @@ Handlers
[raven](https://packagist.org/packages/raven/raven).
- _ZendMonitorHandler_: Logs records to the Zend Monitor present in Zend Server.
- _NewRelicHandler_: Logs records to a [NewRelic](http://newrelic.com/) application.
- _LogglyHandler_: Logs records to a [Loggly](http://www.loggly.com/) account.
- _SyslogUdpHandler_: Logs records to a remote [Syslogd](http://www.rsyslog.com/) server.
### Logging in development
@ -150,6 +149,8 @@ Handlers
[Mongo](http://pecl.php.net/package/mongo) extension connection.
- _CouchDBHandler_: Logs records to a CouchDB server.
- _DoctrineCouchDBHandler_: Logs records to a CouchDB server via the Doctrine CouchDB ODM.
- _ElasticSearchHandler_: Logs records to an Elastic Search server.
- _DynamoDbHandler_: Logs records to a DynamoDB table with the [AWS SDK](https://github.com/aws/aws-sdk-php).
### Wrappers / Special Handlers
@ -178,11 +179,13 @@ Formatters
- _LineFormatter_: Formats a log record into a one-line string.
- _NormalizerFormatter_: Normalizes objects/resources down to strings so a record can easily be serialized/encoded.
- _ScalarFormatter_: Used to format log records into an associative array of scalar values.
- _JsonFormatter_: Encodes a log record into json.
- _WildfireFormatter_: Used to format log records into the Wildfire/FirePHP protocol, only useful for the FirePHPHandler.
- _ChromePHPFormatter_: Used to format log records into the ChromePHP format, only useful for the ChromePHPHandler.
- _GelfFormatter_: Used to format log records into Gelf message instances, only useful for the GelfHandler.
- _LogstashFormatter_: Used to format log records into [logstash](http://logstash.net/) event json, useful for any handler listed under inputs [here](http://logstash.net/docs/1.1.5/).
- _ElasticaFormatter_: Used to format log records into an Elastica\Document object, only useful for the ElasticSearchHandler.
Processors
----------
@ -225,10 +228,11 @@ Frameworks Integration
can be used very easily with Monolog since it implements the interface.
- [Symfony2](http://symfony.com) comes out of the box with Monolog.
- [Silex](http://silex.sensiolabs.org/) comes out of the box with Monolog.
- [Laravel4](http://laravel.com/) comes out of the box with Monolog.
- [Laravel 4](http://laravel.com/) comes out of the box with Monolog.
- [PPI](http://www.ppi.io/) comes out of the box with Monolog.
- [CakePHP](http://cakephp.org/) is usable with Monolog via the [cakephp-monolog](https://github.com/jadb/cakephp-monolog) plugin.
- [Slim](http://www.slimframework.com/) is usable with Monolog via the [Slim-Monolog](https://github.com/Flynsarmy/Slim-Monolog) log writer.
- [XOOPS 2.6](http://xoops.org/) comes out of the box with Monolog.
Author
------

@ -17,23 +17,28 @@
"psr/log": "~1.0"
},
"require-dev": {
"phpunit/phpunit": "~3.7.0",
"mlehner/gelf-php": "1.0.*",
"raven/raven": "0.5.*",
"doctrine/couchdb": "dev-master"
"ruflin/elastica": "0.90.*",
"doctrine/couchdb": "dev-master",
"aws/aws-sdk-php": "~2.4.8"
},
"suggest": {
"mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server",
"raven/raven": "Allow sending log messages to a Sentry server",
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
"ruflin/elastica": "Allow sending log messages to an Elastic Search server",
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
"ext-mongo": "Allow sending log messages to a MongoDB server"
"ext-mongo": "Allow sending log messages to a MongoDB server",
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB"
},
"autoload": {
"psr-0": {"Monolog": "src/"}
},
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
"dev-master": "1.7.x-dev"
}
}
}

@ -7,6 +7,10 @@ Installation
Monolog is available on Packagist ([monolog/monolog](http://packagist.org/packages/monolog/monolog))
and as such installable via [Composer](http://getcomposer.org/).
```bash
php composer.phar require monolog/monolog '~1.4'
```
If you do not use Composer, you can grab the code from GitHub, and use any
PSR-0 compatible autoloader (e.g. the [Symfony2 ClassLoader component](https://github.com/symfony/ClassLoader))
to load Monolog classes.
@ -84,7 +88,7 @@ $logger->pushProcessor(function ($record) {
```
Monolog provides some built-in processors that can be used in your project.
Look at the README file for the list.
Look at the [README file](https://github.com/Seldaek/monolog/blob/master/README.mdown) for the list.
> Tip: processors can also be registered on a specific handler instead of
the logger to apply only for this handler.

@ -72,7 +72,7 @@ class ErrorHandler
public function registerExceptionHandler($level = null, $callPrevious = true)
{
$prev = set_exception_handler(array($this, 'handleException'));
$this->uncaughtExceptionLevel = $level === null ? LogLevel::ERROR : $level;
$this->uncaughtExceptionLevel = $level;
if ($callPrevious && $prev) {
$this->previousExceptionHandler = $prev;
}
@ -81,12 +81,7 @@ class ErrorHandler
public function registerErrorHandler(array $levelMap = array(), $callPrevious = true, $errorTypes = -1)
{
$prev = set_error_handler(array($this, 'handleError'), $errorTypes);
$this->errorLevelMap = $this->defaultErrorLevelMap();
// merging the map into the defaults by hand because array_merge
// trips up on numeric keys
foreach ($levelMap as $key => $val) {
$this->errorLevelMap[$key] = $val;
}
$this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap);
if ($callPrevious) {
$this->previousErrorHandler = $prev ?: true;
}
@ -97,7 +92,7 @@ class ErrorHandler
register_shutdown_function(array($this, 'handleFatalError'));
$this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize);
$this->fatalLevel = $level === null ? LogLevel::ALERT : $level;
$this->fatalLevel = $level;
}
protected function defaultErrorLevelMap()
@ -126,7 +121,11 @@ class ErrorHandler
*/
public function handleException(\Exception $e)
{
$this->logger->log($this->uncaughtExceptionLevel, 'Uncaught exception', array('exception' => $e));
$this->logger->log(
$this->uncaughtExceptionLevel === null ? LogLevel::ERROR : $this->uncaughtExceptionLevel,
'Uncaught exception',
array('exception' => $e)
);
if ($this->previousExceptionHandler) {
call_user_func($this->previousExceptionHandler, $e);
@ -162,7 +161,7 @@ class ErrorHandler
$lastError = error_get_last();
if ($lastError && in_array($lastError['type'], self::$fatalErrors)) {
$this->logger->log(
$this->fatalLevel,
$this->fatalLevel === null ? LogLevel::ALERT : $this->fatalLevel,
'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'],
array('file' => $lastError['file'], 'line' => $lastError['line'])
);

@ -89,6 +89,13 @@ class GelfMessageFormatter extends NormalizerFormatter
$message->setAdditional($this->contextPrefix . $key, is_scalar($val) ? $val : $this->toJson($val));
}
if (null === $message->getFile() && isset($record['context']['exception'])) {
if (preg_match("/^(.+):([0-9]+)$/", $record['context']['exception']['file'], $matches)) {
$message->setFile($matches[1]);
$message->setLine($matches[2]);
}
}
return $message;
}
}

@ -50,8 +50,10 @@ class LineFormatter extends NormalizerFormatter
}
}
foreach ($vars as $var => $val) {
if (false !== strpos($output, '%'.$var.'%')) {
$output = str_replace('%'.$var.'%', $this->convertToString($val), $output);
}
}
return $output;
}
@ -94,9 +96,9 @@ class LineFormatter extends NormalizerFormatter
$data = $this->normalize($data);
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
return $this->toJson($data);
return $this->toJson($data, true);
}
return str_replace('\\/', '/', json_encode($data));
return str_replace('\\/', '/', @json_encode($data));
}
}

@ -21,6 +21,9 @@ namespace Monolog\Formatter;
*/
class LogstashFormatter extends NormalizerFormatter
{
const V0 = 0;
const V1 = 1;
/**
* @var string the name of the system for the Logstash log message, used to fill the @source field
*/
@ -41,22 +44,27 @@ class LogstashFormatter extends NormalizerFormatter
*/
protected $contextPrefix;
/**
* @var integer logstash format version to use
*/
protected $version;
/**
* @param string $applicationName the application that sends the data, used as the "type" field of logstash
* @param string $systemName the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine
* @param string $extraPrefix prefix for extra keys inside logstash "fields"
* @param string $contextPrefix prefix for context keys inside logstash "fields", defaults to ctxt_
*/
public function __construct($applicationName, $systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_')
public function __construct($applicationName, $systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_', $version = self::V0)
{
//log stash requires a ISO 8601 format date
parent::__construct('c');
// logstash requires a ISO 8601 format date with optional millisecond precision.
parent::__construct('Y-m-d\TH:i:s.uP');
$this->systemName = $systemName ?: gethostname();
$this->applicationName = $applicationName;
$this->extraPrefix = $extraPrefix;
$this->contextPrefix = $contextPrefix;
$this->version = $version;
}
/**
@ -65,19 +73,32 @@ class LogstashFormatter extends NormalizerFormatter
public function format(array $record)
{
$record = parent::format($record);
if ($this->version === self::V1) {
$message = $this->formatV1($record);
} else {
$message = $this->formatV0($record);
}
return $this->toJson($message) . "\n";
}
protected function formatV0(array $record)
{
$message = array(
'@timestamp' => $record['datetime'],
'@message' => $record['message'],
'@tags' => array($record['channel']),
'@source' => $this->systemName
'@source' => $this->systemName,
'@fields' => array(
'channel' => $record['channel'],
'level' => $record['level']
)
);
if ($this->applicationName) {
$message['@type'] = $this->applicationName;
}
$message['@fields'] = array();
$message['@fields']['channel'] = $record['channel'];
$message['@fields']['level'] = $record['level'];
if (isset($record['extra']['server'])) {
$message['@source_host'] = $record['extra']['server'];
@ -93,6 +114,33 @@ class LogstashFormatter extends NormalizerFormatter
$message['@fields'][$this->contextPrefix . $key] = $val;
}
return json_encode($message) . "\n";
return $message;
}
protected function formatV1(array $record)
{
$message = array(
'@timestamp' => $record['datetime'],
'@version' => 1,
'message' => $record['message'],
'host' => $this->systemName,
'type' => $record['channel'],
'channel' => $record['channel'],
'level' => $record['level_name']
);
if ($this->applicationName) {
$message['type'] = $this->applicationName;
}
foreach ($record['extra'] as $key => $val) {
$message[$this->extraPrefix . $key] = $val;
}
foreach ($record['context'] as $key => $val) {
$message[$this->contextPrefix . $key] = $val;
}
return $message;
}
}

@ -23,7 +23,7 @@ use Monolog\Formatter\LineFormatter;
abstract class AbstractHandler implements HandlerInterface
{
protected $level = Logger::DEBUG;
protected $bubble = false;
protected $bubble = true;
/**
* @var FormatterInterface
@ -77,6 +77,8 @@ abstract class AbstractHandler implements HandlerInterface
throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given');
}
array_unshift($this->processors, $callback);
return $this;
}
/**
@ -97,6 +99,8 @@ abstract class AbstractHandler implements HandlerInterface
public function setFormatter(FormatterInterface $formatter)
{
$this->formatter = $formatter;
return $this;
}
/**
@ -115,10 +119,13 @@ abstract class AbstractHandler implements HandlerInterface
* Sets minimum logging level at which this handler will be triggered.
*
* @param integer $level
* @return self
*/
public function setLevel($level)
{
$this->level = $level;
return $this;
}
/**
@ -134,19 +141,22 @@ abstract class AbstractHandler implements HandlerInterface
/**
* Sets the bubbling behavior.
*
* @param Boolean $bubble True means that bubbling is not permitted.
* False means that this handler allows bubbling.
* @param Boolean $bubble true means that this handler allows bubbling.
* false means that bubbling is not permitted.
* @return self
*/
public function setBubble($bubble)
{
$this->bubble = $bubble;
return $this;
}
/**
* Gets the bubbling behavior.
*
* @return Boolean True means that bubbling is not permitted.
* False means that this handler allows bubbling.
* @return Boolean true means that this handler allows bubbling.
* false means that bubbling is not permitted.
*/
public function getBubble()
{

@ -26,7 +26,7 @@ abstract class AbstractProcessingHandler extends AbstractHandler
*/
public function handle(array $record)
{
if ($record['level'] < $this->level) {
if (!$this->isHandling($record)) {
return false;
}

@ -31,16 +31,16 @@ class BufferHandler extends AbstractHandler
/**
* @param HandlerInterface $handler Handler.
* @param integer $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
* @param integer $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
* @param integer $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
* @param Boolean $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded
*/
public function __construct(HandlerInterface $handler, $bufferSize = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false)
public function __construct(HandlerInterface $handler, $bufferLimit = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false)
{
parent::__construct($level, $bubble);
$this->handler = $handler;
$this->bufferLimit = (int) $bufferSize;
$this->bufferLimit = (int) $bufferLimit;
$this->flushOnOverflow = $flushOnOverflow;
// __destructor() doesn't get called on Fatal errors

@ -103,7 +103,7 @@ class CubeHandler extends AbstractProcessingHandler
{
$date = $record['datetime'];
$data = array('time' => $date->format('Y-m-d\TH:i:s.u'));
$data = array('time' => $date->format('Y-m-d\TH:i:s.uO'));
unset($record['datetime']);
if (isset($record['context']['type'])) {

@ -20,6 +20,9 @@ use Monolog\Logger;
*/
class ErrorLogHandler extends AbstractProcessingHandler
{
const OPERATING_SYSTEM = 0;
const SAPI = 4;
protected $messageType;
/**
@ -27,15 +30,29 @@ class ErrorLogHandler extends AbstractProcessingHandler
* @param integer $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct($messageType = 0, $level = Logger::DEBUG, $bubble = true)
public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, $bubble = true)
{
parent::__construct($level, $bubble);
if (!in_array($messageType, array(0, 4))) {
throw new \InvalidArgumentException('Only message types 0 and 4 are supported');
if (false === in_array($messageType, self::getAvailableTypes())) {
$message = sprintf('The given message type "%s" is not supported', print_r($messageType, true));
throw new \InvalidArgumentException($message);
}
$this->messageType = $messageType;
}
/**
* @return array With all available types
*/
public static function getAvailableTypes()
{
return array(
self::OPERATING_SYSTEM,
self::SAPI,
);
}
/**
* {@inheritdoc}
*/

@ -46,8 +46,8 @@ interface HandlerInterface
* calling further handlers in the stack with a given log record.
*
* @param array $record The record to handle
* @return Boolean True means that this handler handled the record, and that bubbling is not permitted.
* False means the record was either not processed or that this handler allows bubbling.
* @return Boolean true means that this handler handled the record, and that bubbling is not permitted.
* false means the record was either not processed or that this handler allows bubbling.
*/
public function handle(array $record);
@ -62,6 +62,7 @@ interface HandlerInterface
* Adds a processor in the stack.
*
* @param callable $callback
* @return self
*/
public function pushProcessor($callback);
@ -76,6 +77,7 @@ interface HandlerInterface
* Sets the formatter.
*
* @param FormatterInterface $formatter
* @return self
*/
public function setFormatter(FormatterInterface $formatter);

@ -150,4 +150,70 @@ class HipChatHandler extends SocketHandler
$this->closeSocket();
}
/**
* {@inheritdoc}
*/
public function handleBatch(array $records)
{
if (count($records) == 0) {
return true;
}
$batchRecord = $this->combineRecords($records);
if (!$this->isHandling($batchRecord)) {
return false;
}
$this->write($batchRecord);
return false === $this->bubble;
}
/**
* Combines multiple records into one. Error level of the combined record
* will be the highest level from the given records. Datetime will be taken
* from the first record.
*
* @param $records
* @return array
*/
private function combineRecords($records)
{
$messages = array();
$formattedMessages = array();
$level = 0;
$levelName = null;
$datetime = null;
foreach ($records as $record) {
$record = $this->processRecord($record);
$record['formatted'] = $this->getFormatter()->format($record);
$messages[] = $record['message'];
$formattedMessages[] = $record['formatted'];
if ($record['level'] > $level) {
$level = $record['level'];
$levelName = $record['level_name'];
}
if (null === $datetime) {
$datetime = $record['datetime'];
}
}
$batchRecord = array(
'message' => implode(PHP_EOL, $messages),
'formatted' => implode('', $formattedMessages),
'level' => $level,
'level_name' => $levelName,
'datetime' => $datetime,
'context' => array(),
'extra' => array(),
);
return $batchRecord;
}
}

@ -3,7 +3,7 @@
/*
* This file is part of the Monolog package.
*
* (c) Thomas Tourlourat <thomas@tourlourat.com>
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@ -27,7 +27,7 @@ use Monolog\Formatter\NormalizerFormatter;
*/
class MongoDBHandler extends AbstractProcessingHandler
{
private $mongoCollection;
protected $mongoCollection;
public function __construct($mongo, $database, $collection, $level = Logger::DEBUG, $bubble = true)
{

@ -25,6 +25,7 @@ class NativeMailerHandler extends MailHandler
protected $headers = array(
'Content-type: text/plain; charset=utf-8'
);
protected $maxColumnWidth;
/**
* @param string|array $to The receiver of the mail
@ -32,13 +33,15 @@ class NativeMailerHandler extends MailHandler
* @param string $from The sender of the mail
* @param integer $level The minimum logging level at which this handler will be triggered
* @param boolean $bubble Whether the messages that are handled can bubble up the stack or not
* @param int $maxColumnWidth The maximum column width that the message lines will have
*/
public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubble = true)
public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubble = true, $maxColumnWidth = 70)
{
parent::__construct($level, $bubble);
$this->to = is_array($to) ? $to : array($to);
$this->subject = $subject;
$this->addHeader(sprintf('From: %s', $from));
$this->maxColumnWidth = $maxColumnWidth;
}
/**
@ -59,7 +62,7 @@ class NativeMailerHandler extends MailHandler
*/
protected function send($content, array $records)
{
$content = wordwrap($content, 70);
$content = wordwrap($content, $this->maxColumnWidth);
$headers = implode("\r\n", $this->headers) . "\r\n";
foreach ($this->to as $to) {
mail($to, $this->subject, $content, $headers);

@ -20,12 +20,23 @@ use Monolog\Logger;
*/
class NewRelicHandler extends AbstractProcessingHandler
{
/**
* Name of the New Relic application that will receive logs from this handler.
*
* @var string
*/
protected $appName;
/**
* {@inheritDoc}
*
* @param string $appName
*/
public function __construct($level = Logger::ERROR, $bubble = true)
public function __construct($level = Logger::ERROR, $bubble = true, $appName = null)
{
parent::__construct($level, $bubble);
$this->appName = $appName;
}
/**
@ -37,6 +48,10 @@ class NewRelicHandler extends AbstractProcessingHandler
throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler');
}
if ($appName = $this->getAppName($record['context'])) {
$this->setNewRelicAppName($appName);
}
if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) {
newrelic_notice_error($record['message'], $record['context']['exception']);
unset($record['context']['exception']);
@ -58,4 +73,30 @@ class NewRelicHandler extends AbstractProcessingHandler
{
return extension_loaded('newrelic');
}
/**
* Returns the appname where this log should be sent. Each log can override the default appname, set in this
* handler's constructor, by providing the appname in its context.
*
* @param array $context
* @return null|string
*/
protected function getAppName(array $context)
{
if (isset($context['appname'])) {
return $context['appname'];
}
return $this->appName;
}
/**
* Sets the NewRelic application that should receive this log.
*
* @param string $appName
*/
protected function setNewRelicAppName($appName)
{
newrelic_set_appname($appName);
}
}

@ -25,6 +25,8 @@ class PushoverHandler extends SocketHandler
private $users;
private $title;
private $user;
private $retry;
private $expire;
private $highPriorityLevel;
private $emergencyLevel;
@ -41,8 +43,10 @@ class PushoverHandler extends SocketHandler
* sending "high priority" requests to the Pushover API
* @param integer $emergencyLevel The minimum logging level at which this handler will start
* sending "emergency" requests to the Pushover API
* @param integer $retry The retry parameter specifies how often (in seconds) the Pushover servers will send the same notification to the user.
* @param integer $expire The expire parameter specifies how many seconds your notification will continue to be retried for (every retry seconds).
*/
public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY)
public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY, $retry = 30, $expire = 25200)
{
$connectionString = $useSSL ? 'ssl://api.pushover.net:443' : 'api.pushover.net:80';
parent::__construct($connectionString, $level, $bubble);
@ -52,6 +56,8 @@ class PushoverHandler extends SocketHandler
$this->title = $title ?: gethostname();
$this->highPriorityLevel = $highPriorityLevel;
$this->emergencyLevel = $emergencyLevel;
$this->retry = $retry;
$this->expire = $expire;
}
protected function generateDataStream($record)
@ -78,6 +84,8 @@ class PushoverHandler extends SocketHandler
if ($record['level'] >= $this->emergencyLevel) {
$dataArray['priority'] = 2;
$dataArray['retry'] = $this->retry;
$dataArray['expire'] = $this->expire;
} elseif ($record['level'] >= $this->highPriorityLevel) {
$dataArray['priority'] = 1;
}

@ -80,10 +80,10 @@ class RavenHandler extends AbstractProcessingHandler
// the record with the highest severity is the "main" one
$record = array_reduce($records, function($highest, $record) {
if ($record['level'] >= $highest['level']) {
$highest = $record;
return $record;
}
return $highest;
}
});
// the other ones are added as a context item

@ -3,7 +3,7 @@
/*
* This file is part of the Monolog package.
*
* (c) Thomas Tourlourat <thomas@tourlourat.com>
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

@ -28,6 +28,8 @@ class RotatingFileHandler extends StreamHandler
protected $maxFiles;
protected $mustRotate;
protected $nextRotation;
protected $filenameFormat;
protected $dateFormat;
/**
* @param string $filename
@ -40,6 +42,8 @@ class RotatingFileHandler extends StreamHandler
$this->filename = $filename;
$this->maxFiles = (int) $maxFiles;
$this->nextRotation = new \DateTime('tomorrow');
$this->filenameFormat = '{filename}-{date}';
$this->dateFormat = 'Y-m-d';
parent::__construct($this->getTimedFilename(), $level, $bubble);
}
@ -56,6 +60,12 @@ class RotatingFileHandler extends StreamHandler
}
}
public function setFilenameFormat($filenameFormat, $dateFormat)
{
$this->filenameFormat = $filenameFormat;
$this->dateFormat = $dateFormat;
}
/**
* {@inheritdoc}
*/
@ -88,12 +98,7 @@ class RotatingFileHandler extends StreamHandler
return;
}
$fileInfo = pathinfo($this->filename);
$glob = $fileInfo['dirname'].'/'.$fileInfo['filename'].'-*';
if (!empty($fileInfo['extension'])) {
$glob .= '.'.$fileInfo['extension'];
}
$logFiles = glob($glob);
$logFiles = glob($this->getGlobPattern());
if ($this->maxFiles >= count($logFiles)) {
// no files to remove
return;
@ -114,11 +119,31 @@ class RotatingFileHandler extends StreamHandler
protected function getTimedFilename()
{
$fileInfo = pathinfo($this->filename);
$timedFilename = $fileInfo['dirname'].'/'.$fileInfo['filename'].'-'.date('Y-m-d');
$timedFilename = str_replace(
array('{filename}', '{date}'),
array($fileInfo['filename'], date($this->dateFormat)),
$fileInfo['dirname'] . '/' . $this->filenameFormat
);
if (!empty($fileInfo['extension'])) {
$timedFilename .= '.'.$fileInfo['extension'];
}
return $timedFilename;
}
protected function getGlobPattern()
{
$fileInfo = pathinfo($this->filename);
$glob = str_replace(
array('{filename}', '{date}'),
array($fileInfo['filename'], '*'),
$fileInfo['dirname'] . '/' . $this->filenameFormat
);
if (!empty($fileInfo['extension'])) {
$glob .= '.'.$fileInfo['extension'];
}
return $glob;
}
}

@ -24,6 +24,7 @@ class StreamHandler extends AbstractProcessingHandler
{
protected $stream;
protected $url;
private $errorMessage;
/**
* @param string $stream
@ -60,17 +61,19 @@ class StreamHandler extends AbstractProcessingHandler
if (!$this->url) {
throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().');
}
$errorMessage = null;
set_error_handler(function ($code, $msg) use (&$errorMessage) {
$errorMessage = preg_replace('{^fopen\(.*?\): }', '', $msg);
});
$this->errorMessage = null;
set_error_handler(array($this, 'customErrorHandler'));
$this->stream = fopen($this->url, 'a');
restore_error_handler();
if (!is_resource($this->stream)) {
$this->stream = null;
throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$errorMessage, $this->url));
throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$this->errorMessage, $this->url));
}
}
fwrite($this->stream, (string) $record['formatted']);
}
private function customErrorHandler($code, $msg) {
$this->errorMessage = preg_replace('{^fopen\(.*?\): }', '', $msg);
}
}

@ -12,7 +12,6 @@
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Formatter\LineFormatter;
/**
* Logs to syslog service.
@ -27,42 +26,10 @@ use Monolog\Formatter\LineFormatter;
*
* @author Sven Paulus <sven@karlsruhe.org>
*/
class SyslogHandler extends AbstractProcessingHandler
class SyslogHandler extends AbstractSyslogHandler
{
protected $ident;
protected $logopts;
protected $facility;
/**
* Translates Monolog log levels to syslog log priorities.
*/
private $logLevels = array(
Logger::DEBUG => LOG_DEBUG,
Logger::INFO => LOG_INFO,
Logger::NOTICE => LOG_NOTICE,
Logger::WARNING => LOG_WARNING,
Logger::ERROR => LOG_ERR,
Logger::CRITICAL => LOG_CRIT,
Logger::ALERT => LOG_ALERT,
Logger::EMERGENCY => LOG_EMERG,
);
/**
* List of valid log facility names.
*/
private $facilities = array(
'auth' => LOG_AUTH,
'authpriv' => LOG_AUTHPRIV,
'cron' => LOG_CRON,
'daemon' => LOG_DAEMON,
'kern' => LOG_KERN,
'lpr' => LOG_LPR,
'mail' => LOG_MAIL,
'news' => LOG_NEWS,
'syslog' => LOG_SYSLOG,
'user' => LOG_USER,
'uucp' => LOG_UUCP,
);
/**
* @param string $ident
@ -73,29 +40,10 @@ class SyslogHandler extends AbstractProcessingHandler
*/
public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $logopts = LOG_PID)
{
parent::__construct($level, $bubble);
if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->facilities['local0'] = LOG_LOCAL0;
$this->facilities['local1'] = LOG_LOCAL1;
$this->facilities['local2'] = LOG_LOCAL2;
$this->facilities['local3'] = LOG_LOCAL3;
$this->facilities['local4'] = LOG_LOCAL4;
$this->facilities['local5'] = LOG_LOCAL5;
$this->facilities['local6'] = LOG_LOCAL6;
$this->facilities['local7'] = LOG_LOCAL7;
}
// convert textual description of facility to syslog constant
if (array_key_exists(strtolower($facility), $this->facilities)) {
$facility = $this->facilities[strtolower($facility)];
} elseif (!in_array($facility, array_values($this->facilities), true)) {
throw new \UnexpectedValueException('Unknown facility value "'.$facility.'" given');
}
parent::__construct($facility, $level, $bubble);
$this->ident = $ident;
$this->logopts = $logopts;
$this->facility = $facility;
}
/**
@ -116,12 +64,4 @@ class SyslogHandler extends AbstractProcessingHandler
}
syslog($this->logLevels[$record['level']], (string) $record['formatted']);
}
/**
* {@inheritdoc}
*/
protected function getDefaultFormatter()
{
return new LineFormatter('%channel%.%level_name%: %message% %context% %extra%');
}
}

@ -86,6 +86,11 @@ class Logger implements LoggerInterface
*/
const API = 1;
/**
* Logging levels from syslog protocol defined in RFC 5424
*
* @var array $levels Logging levels
*/
protected static $levels = array(
100 => 'DEBUG',
200 => 'INFO',

@ -11,6 +11,8 @@
namespace Monolog\Processor;
use Monolog\Logger;
/**
* Injects line/file:class/function where the log message came from
*
@ -24,12 +26,24 @@ namespace Monolog\Processor;
*/
class IntrospectionProcessor
{
private $level;
public function __construct($level = Logger::DEBUG)
{
$this->level = $level;
}
/**
* @param array $record
* @return array
*/
public function __invoke(array $record)
{
// return if the level is not high enough
if ($record['level'] < $this->level) {
return $record;
}
$trace = debug_backtrace();
// skip first since it's always the current method

@ -18,22 +18,13 @@ namespace Monolog\Processor;
*/
class ProcessIdProcessor
{
private static $pid;
public function __construct()
{
if (null === self::$pid) {
self::$pid = getmypid();
}
}
/**
* @param array $record
* @return array
*/
public function __invoke(array $record)
{
$record['extra']['process_id'] = self::$pid;
$record['extra']['process_id'] = getmypid();
return $record;
}

@ -57,6 +57,10 @@ class WebProcessor
)
);
if (isset($this->serverData['UNIQUE_ID'])) {
$record['extra']['unique_id'] = $this->serverData['UNIQUE_ID'];
}
return $record;
}
}

@ -1,31 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog;
use Monolog\Handler\TestHandler;
class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
{
public function testHandleError()
{
$logger = new Logger('test', array($handler = new TestHandler));
$errHandler = new ErrorHandler($logger);
$errHandler->registerErrorHandler(array(E_USER_NOTICE => Logger::EMERGENCY), false);
trigger_error('Foo', E_USER_ERROR);
$this->assertCount(1, $handler->getRecords());
$this->assertTrue($handler->hasErrorRecords());
trigger_error('Foo', E_USER_NOTICE);
$this->assertCount(2, $handler->getRecords());
$this->assertTrue($handler->hasEmergencyRecords());
}
}

@ -1,158 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
use Monolog\Logger;
class ChromePHPFormatterTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers Monolog\Formatter\ChromePHPFormatter::format
*/
public function testDefaultFormat()
{
$formatter = new ChromePHPFormatter();
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array('from' => 'logger'),
'datetime' => new \DateTime("@0"),
'extra' => array('ip' => '127.0.0.1'),
'message' => 'log',
);
$message = $formatter->format($record);
$this->assertEquals(
array(
'meh',
array(
'message' => 'log',
'context' => array('from' => 'logger'),
'extra' => array('ip' => '127.0.0.1'),
),
'unknown',
'error'
),
$message
);
}
/**
* @covers Monolog\Formatter\ChromePHPFormatter::format
*/
public function testFormatWithFileAndLine()
{
$formatter = new ChromePHPFormatter();
$record = array(
'level' => Logger::CRITICAL,
'level_name' => 'CRITICAL',
'channel' => 'meh',
'context' => array('from' => 'logger'),
'datetime' => new \DateTime("@0"),
'extra' => array('ip' => '127.0.0.1', 'file' => 'test', 'line' => 14),
'message' => 'log',
);
$message = $formatter->format($record);
$this->assertEquals(
array(
'meh',
array(
'message' => 'log',
'context' => array('from' => 'logger'),
'extra' => array('ip' => '127.0.0.1'),
),
'test : 14',
'error'
),
$message
);
}
/**
* @covers Monolog\Formatter\ChromePHPFormatter::format
*/
public function testFormatWithoutContext()
{
$formatter = new ChromePHPFormatter();
$record = array(
'level' => Logger::DEBUG,
'level_name' => 'DEBUG',
'channel' => 'meh',
'context' => array(),
'datetime' => new \DateTime("@0"),
'extra' => array(),
'message' => 'log',
);
$message = $formatter->format($record);
$this->assertEquals(
array(
'meh',
'log',
'unknown',
'log'
),
$message
);
}
/**
* @covers Monolog\Formatter\ChromePHPFormatter::formatBatch
*/
public function testBatchFormatThrowException()
{
$formatter = new ChromePHPFormatter();
$records = array(
array(
'level' => Logger::INFO,
'level_name' => 'INFO',
'channel' => 'meh',
'context' => array(),
'datetime' => new \DateTime("@0"),
'extra' => array(),
'message' => 'log',
),
array(
'level' => Logger::WARNING,
'level_name' => 'WARNING',
'channel' => 'foo',
'context' => array(),
'datetime' => new \DateTime("@0"),
'extra' => array(),
'message' => 'log2',
),
);
$this->assertEquals(
array(
array(
'meh',
'log',
'unknown',
'info'
),
array(
'foo',
'log2',
'unknown',
'warn'
),
),
$formatter->formatBatch($records)
);
}
}

@ -1,158 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
use Monolog\Logger;
use Monolog\Formatter\GelfMessageFormatter;
class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase
{
public function setUp()
{
if (!class_exists("Gelf\Message")) {
$this->markTestSkipped("mlehner/gelf-php not installed");
}
}
/**
* @covers Monolog\Formatter\GelfMessageFormatter::format
*/
public function testDefaultFormatter()
{
$formatter = new GelfMessageFormatter();
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array(),
'datetime' => new \DateTime("@0"),
'extra' => array(),
'message' => 'log',
);
$message = $formatter->format($record);
$this->assertInstanceOf('Gelf\Message', $message);
$this->assertEquals(0, $message->getTimestamp());
$this->assertEquals('log', $message->getShortMessage());
$this->assertEquals('meh', $message->getFacility());
$this->assertEquals(null, $message->getLine());
$this->assertEquals(null, $message->getFile());
$this->assertEquals(3, $message->getLevel());
$this->assertNotEmpty($message->getHost());
$formatter = new GelfMessageFormatter('mysystem');
$message = $formatter->format($record);
$this->assertInstanceOf('Gelf\Message', $message);
$this->assertEquals('mysystem', $message->getHost());
}
/**
* @covers Monolog\Formatter\GelfMessageFormatter::format
*/
public function testFormatWithFileAndLine()
{
$formatter = new GelfMessageFormatter();
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array('from' => 'logger'),
'datetime' => new \DateTime("@0"),
'extra' => array('file' => 'test', 'line' => 14),
'message' => 'log',
);
$message = $formatter->format($record);
$this->assertInstanceOf('Gelf\Message', $message);
$this->assertEquals('test', $message->getFile());
$this->assertEquals(14, $message->getLine());
}
/**
* @covers Monolog\Formatter\GelfMessageFormatter::format
*/
public function testFormatWithContext()
{
$formatter = new GelfMessageFormatter();
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array('from' => 'logger'),
'datetime' => new \DateTime("@0"),
'extra' => array('key' => 'pair'),
'message' => 'log'
);
$message = $formatter->format($record);
$this->assertInstanceOf('Gelf\Message', $message);
$message_array = $message->toArray();
$this->assertArrayHasKey('_ctxt_from', $message_array);
$this->assertEquals('logger', $message_array['_ctxt_from']);
// Test with extraPrefix
$formatter = new GelfMessageFormatter(null, null, 'CTX');
$message = $formatter->format($record);
$this->assertInstanceOf('Gelf\Message', $message);
$message_array = $message->toArray();
$this->assertArrayHasKey('_CTXfrom', $message_array);
$this->assertEquals('logger', $message_array['_CTXfrom']);
}
/**
* @covers Monolog\Formatter\GelfMessageFormatter::format
*/
public function testFormatWithExtra()
{
$formatter = new GelfMessageFormatter();
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array('from' => 'logger'),
'datetime' => new \DateTime("@0"),
'extra' => array('key' => 'pair'),
'message' => 'log'
);
$message = $formatter->format($record);
$this->assertInstanceOf('Gelf\Message', $message);
$message_array = $message->toArray();
$this->assertArrayHasKey('_key', $message_array);
$this->assertEquals('pair', $message_array['_key']);
// Test with extraPrefix
$formatter = new GelfMessageFormatter(null, 'EXT');
$message = $formatter->format($record);
$this->assertInstanceOf('Gelf\Message', $message);
$message_array = $message->toArray();
$this->assertArrayHasKey('_EXTkey', $message_array);
$this->assertEquals('pair', $message_array['_EXTkey']);
}
}

@ -1,41 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
use Monolog\Logger;
use Monolog\TestCase;
class JsonFormatterTest extends TestCase
{
/**
* @covers Monolog\Formatter\JsonFormatter::format
*/
public function testFormat()
{
$formatter = new JsonFormatter();
$record = $this->getRecord();
$this->assertEquals(json_encode($record), $formatter->format($record));
}
/**
* @covers Monolog\Formatter\JsonFormatter::formatBatch
*/
public function testFormatBatch()
{
$formatter = new JsonFormatter();
$records = array(
$this->getRecord(Logger::WARNING),
$this->getRecord(Logger::DEBUG),
);
$this->assertEquals(json_encode($records), $formatter->formatBatch($records));
}
}

@ -1,164 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
/**
* @covers Monolog\Formatter\LineFormatter
*/
class LineFormatterTest extends \PHPUnit_Framework_TestCase
{
public function testDefFormatWithString()
{
$formatter = new LineFormatter(null, 'Y-m-d');
$message = $formatter->format(array(
'level_name' => 'WARNING',
'channel' => 'log',
'context' => array(),
'message' => 'foo',
'datetime' => new \DateTime,
'extra' => array(),
));
$this->assertEquals('['.date('Y-m-d').'] log.WARNING: foo [] []'."\n", $message);
}
public function testDefFormatWithArrayContext()
{
$formatter = new LineFormatter(null, 'Y-m-d');
$message = $formatter->format(array(
'level_name' => 'ERROR',
'channel' => 'meh',
'message' => 'foo',
'datetime' => new \DateTime,
'extra' => array(),
'context' => array(
'foo' => 'bar',
'baz' => 'qux',
)
));
$this->assertEquals('['.date('Y-m-d').'] meh.ERROR: foo {"foo":"bar","baz":"qux"} []'."\n", $message);
}
public function testDefFormatExtras()
{
$formatter = new LineFormatter(null, 'Y-m-d');
$message = $formatter->format(array(
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array(),
'datetime' => new \DateTime,
'extra' => array('ip' => '127.0.0.1'),
'message' => 'log',
));
$this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log [] {"ip":"127.0.0.1"}'."\n", $message);
}
public function testFormatExtras()
{
$formatter = new LineFormatter("[%datetime%] %channel%.%level_name%: %message% %context% %extra.file% %extra%\n", 'Y-m-d');
$message = $formatter->format(array(
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array(),
'datetime' => new \DateTime,
'extra' => array('ip' => '127.0.0.1', 'file' => 'test'),
'message' => 'log',
));
$this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log [] test {"ip":"127.0.0.1"}'."\n", $message);
}
public function testDefFormatWithObject()
{
$formatter = new LineFormatter(null, 'Y-m-d');
$message = $formatter->format(array(
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array(),
'datetime' => new \DateTime,
'extra' => array('foo' => new TestFoo, 'bar' => new TestBar, 'baz' => array(), 'res' => fopen('php://memory', 'rb')),
'message' => 'foobar',
));
$this->assertEquals('['.date('Y-m-d').'] meh.ERROR: foobar [] {"foo":"[object] (Monolog\\\\Formatter\\\\TestFoo: {\\"foo\\":\\"foo\\"})","bar":"[object] (Monolog\\\\Formatter\\\\TestBar: {})","baz":[],"res":"[resource]"}'."\n", $message);
}
public function testDefFormatWithException()
{
$formatter = new LineFormatter(null, 'Y-m-d');
$message = $formatter->format(array(
'level_name' => 'CRITICAL',
'channel' => 'core',
'context' => array('exception' => new \RuntimeException('Foo')),
'datetime' => new \DateTime,
'extra' => array(),
'message' => 'foobar',
));
$path = str_replace('\\/', '/', json_encode(__FILE__));
$this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException: Foo at '.substr($path, 1, -1).':'.(__LINE__-8).')"} []'."\n", $message);
}
public function testDefFormatWithPreviousException()
{
$formatter = new LineFormatter(null, 'Y-m-d');
$previous = new \LogicException('Wut?');
$message = $formatter->format(array(
'level_name' => 'CRITICAL',
'channel' => 'core',
'context' => array('exception' => new \RuntimeException('Foo', 0, $previous)),
'datetime' => new \DateTime,
'extra' => array(),
'message' => 'foobar',
));
$path = str_replace('\\/', '/', json_encode(__FILE__));
$this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException: Foo at '.substr($path, 1, -1).':'.(__LINE__-8).', LogicException: Wut? at '.substr($path, 1, -1).':'.(__LINE__-12).')"} []'."\n", $message);
}
public function testBatchFormat()
{
$formatter = new LineFormatter(null, 'Y-m-d');
$message = $formatter->formatBatch(array(
array(
'level_name' => 'CRITICAL',
'channel' => 'test',
'message' => 'bar',
'context' => array(),
'datetime' => new \DateTime,
'extra' => array(),
),
array(
'level_name' => 'WARNING',
'channel' => 'log',
'message' => 'foo',
'context' => array(),
'datetime' => new \DateTime,
'extra' => array(),
),
));
$this->assertEquals('['.date('Y-m-d').'] test.CRITICAL: bar [] []'."\n".'['.date('Y-m-d').'] log.WARNING: foo [] []'."\n", $message);
}
}
class TestFoo
{
public $foo = 'foo';
}
class TestBar
{
public function __toString()
{
return 'bar';
}
}

@ -1,160 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
use Monolog\Logger;
use Monolog\Formatter\LogstashFormatter;
class LogstashFormatterTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers Monolog\Formatter\LogstashFormatter::format
*/
public function testDefaultFormatter()
{
$formatter = new LogstashFormatter('test', 'hostname');
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array(),
'datetime' => new \DateTime("@0"),
'extra' => array(),
'message' => 'log',
);
$message = json_decode($formatter->format($record), true);
$this->assertEquals("1970-01-01T00:00:00+00:00", $message['@timestamp']);
$this->assertEquals('log', $message['@message']);
$this->assertEquals('meh', $message['@fields']['channel']);
$this->assertContains('meh', $message['@tags']);
$this->assertEquals(Logger::ERROR, $message['@fields']['level']);
$this->assertEquals('test', $message['@type']);
$this->assertEquals('hostname', $message['@source']);
$formatter = new LogstashFormatter('mysystem');
$message = json_decode($formatter->format($record), true);
$this->assertEquals('mysystem', $message['@type']);
}
/**
* @covers Monolog\Formatter\LogstashFormatter::format
*/
public function testFormatWithFileAndLine()
{
$formatter = new LogstashFormatter('test');
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array('from' => 'logger'),
'datetime' => new \DateTime("@0"),
'extra' => array('file' => 'test', 'line' => 14),
'message' => 'log',
);
$message = json_decode($formatter->format($record), true);
$this->assertEquals('test', $message['@fields']['file']);
$this->assertEquals(14, $message['@fields']['line']);
}
/**
* @covers Monolog\Formatter\LogstashFormatter::format
*/
public function testFormatWithContext()
{
$formatter = new LogstashFormatter('test');
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array('from' => 'logger'),
'datetime' => new \DateTime("@0"),
'extra' => array('key' => 'pair'),
'message' => 'log'
);
$message = json_decode($formatter->format($record), true);
$message_array = $message['@fields'];
$this->assertArrayHasKey('ctxt_from', $message_array);
$this->assertEquals('logger', $message_array['ctxt_from']);
// Test with extraPrefix
$formatter = new LogstashFormatter('test', null, null, 'CTX');
$message = json_decode($formatter->format($record), true);
$message_array = $message['@fields'];
$this->assertArrayHasKey('CTXfrom', $message_array);
$this->assertEquals('logger', $message_array['CTXfrom']);
}
/**
* @covers Monolog\Formatter\LogstashFormatter::format
*/
public function testFormatWithExtra()
{
$formatter = new LogstashFormatter('test');
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array('from' => 'logger'),
'datetime' => new \DateTime("@0"),
'extra' => array('key' => 'pair'),
'message' => 'log'
);
$message = json_decode($formatter->format($record), true);
$message_array = $message['@fields'];
$this->assertArrayHasKey('key', $message_array);
$this->assertEquals('pair', $message_array['key']);
// Test with extraPrefix
$formatter = new LogstashFormatter('test', null, 'EXT');
$message = json_decode($formatter->format($record), true);
$message_array = $message['@fields'];
$this->assertArrayHasKey('EXTkey', $message_array);
$this->assertEquals('pair', $message_array['EXTkey']);
}
public function testFormatWithApplicationName()
{
$formatter = new LogstashFormatter('app', 'test');
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array('from' => 'logger'),
'datetime' => new \DateTime("@0"),
'extra' => array('key' => 'pair'),
'message' => 'log'
);
$message = json_decode($formatter->format($record), true);
$this->assertArrayHasKey('@type', $message);
$this->assertEquals('app', $message['@type']);
}
}

@ -1,182 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
/**
* @covers Monolog\Formatter\NormalizerFormatter
*/
class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase
{
public function testFormat()
{
$formatter = new NormalizerFormatter('Y-m-d');
$formatted = $formatter->format(array(
'level_name' => 'ERROR',
'channel' => 'meh',
'message' => 'foo',
'datetime' => new \DateTime,
'extra' => array('foo' => new TestFooNorm, 'bar' => new TestBarNorm, 'baz' => array(), 'res' => fopen('php://memory', 'rb')),
'context' => array(
'foo' => 'bar',
'baz' => 'qux',
),
));
$this->assertEquals(array(
'level_name' => 'ERROR',
'channel' => 'meh',
'message' => 'foo',
'datetime' => date('Y-m-d'),
'extra' => array(
'foo' => '[object] (Monolog\\Formatter\\TestFooNorm: {"foo":"foo"})',
'bar' => '[object] (Monolog\\Formatter\\TestBarNorm: {})',
'baz' => array(),
'res' => '[resource]',
),
'context' => array(
'foo' => 'bar',
'baz' => 'qux',
)
), $formatted);
}
public function testFormatExceptions()
{
$formatter = new NormalizerFormatter('Y-m-d');
$e = new \LogicException('bar');
$e2 = new \RuntimeException('foo', 0, $e);
$formatted = $formatter->format(array(
'exception' => $e2,
));
$this->assertGreaterThan(5, count($formatted['exception']['trace']));
$this->assertTrue(isset($formatted['exception']['previous']));
unset($formatted['exception']['trace'], $formatted['exception']['previous']);
$this->assertEquals(array(
'exception' => array(
'class' => get_class($e2),
'message' => $e2->getMessage(),
'file' => $e2->getFile().':'.$e2->getLine(),
)
), $formatted);
}
public function testBatchFormat()
{
$formatter = new NormalizerFormatter('Y-m-d');
$formatted = $formatter->formatBatch(array(
array(
'level_name' => 'CRITICAL',
'channel' => 'test',
'message' => 'bar',
'context' => array(),
'datetime' => new \DateTime,
'extra' => array(),
),
array(
'level_name' => 'WARNING',
'channel' => 'log',
'message' => 'foo',
'context' => array(),
'datetime' => new \DateTime,
'extra' => array(),
),
));
$this->assertEquals(array(
array(
'level_name' => 'CRITICAL',
'channel' => 'test',
'message' => 'bar',
'context' => array(),
'datetime' => date('Y-m-d'),
'extra' => array(),
),
array(
'level_name' => 'WARNING',
'channel' => 'log',
'message' => 'foo',
'context' => array(),
'datetime' => date('Y-m-d'),
'extra' => array(),
),
), $formatted);
}
/**
* Test issue #137
*/
public function testIgnoresRecursiveObjectReferences()
{
// set up the recursion
$foo = new \stdClass();
$bar = new \stdClass();
$foo->bar = $bar;
$bar->foo = $foo;
// set an error handler to assert that the error is not raised anymore
$that = $this;
set_error_handler(function ($level, $message, $file, $line, $context) use ($that) {
if (error_reporting() & $level) {
restore_error_handler();
$that->fail("$message should not be raised");
}
});
$formatter = new NormalizerFormatter();
$reflMethod = new \ReflectionMethod($formatter, 'toJson');
$reflMethod->setAccessible(true);
$res = $reflMethod->invoke($formatter, array($foo, $bar), true);
restore_error_handler();
$this->assertEquals(@json_encode(array($foo, $bar)), $res);
}
public function testIgnoresInvalidTypes()
{
// set up the recursion
$resource = fopen(__FILE__, 'r');
// set an error handler to assert that the error is not raised anymore
$that = $this;
set_error_handler(function ($level, $message, $file, $line, $context) use ($that) {
if (error_reporting() & $level) {
restore_error_handler();
$that->fail("$message should not be raised");
}
});
$formatter = new NormalizerFormatter();
$reflMethod = new \ReflectionMethod($formatter, 'toJson');
$reflMethod->setAccessible(true);
$res = $reflMethod->invoke($formatter, array($resource), true);
restore_error_handler();
$this->assertEquals(@json_encode(array($resource)), $res);
}
}
class TestFooNorm
{
public $foo = 'foo';
}
class TestBarNorm
{
public function __toString()
{
return 'bar';
}
}

@ -1,111 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
use Monolog\Logger;
class WildfireFormatterTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers Monolog\Formatter\WildfireFormatter::format
*/
public function testDefaultFormat()
{
$wildfire = new WildfireFormatter();
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array('from' => 'logger'),
'datetime' => new \DateTime("@0"),
'extra' => array('ip' => '127.0.0.1'),
'message' => 'log',
);
$message = $wildfire->format($record);
$this->assertEquals(
'125|[{"Type":"ERROR","File":"","Line":"","Label":"meh"},'
.'{"message":"log","context":{"from":"logger"},"extra":{"ip":"127.0.0.1"}}]|',
$message
);
}
/**
* @covers Monolog\Formatter\WildfireFormatter::format
*/
public function testFormatWithFileAndLine()
{
$wildfire = new WildfireFormatter();
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array('from' => 'logger'),
'datetime' => new \DateTime("@0"),
'extra' => array('ip' => '127.0.0.1', 'file' => 'test', 'line' => 14),
'message' => 'log',
);
$message = $wildfire->format($record);
$this->assertEquals(
'129|[{"Type":"ERROR","File":"test","Line":14,"Label":"meh"},'
.'{"message":"log","context":{"from":"logger"},"extra":{"ip":"127.0.0.1"}}]|',
$message
);
}
/**
* @covers Monolog\Formatter\WildfireFormatter::format
*/
public function testFormatWithoutContext()
{
$wildfire = new WildfireFormatter();
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array(),
'datetime' => new \DateTime("@0"),
'extra' => array(),
'message' => 'log',
);
$message = $wildfire->format($record);
$this->assertEquals(
'58|[{"Type":"ERROR","File":"","Line":"","Label":"meh"},"log"]|',
$message
);
}
/**
* @covers Monolog\Formatter\WildfireFormatter::formatBatch
* @expectedException BadMethodCallException
*/
public function testBatchFormatThrowException()
{
$wildfire = new WildfireFormatter();
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'context' => array(),
'datetime' => new \DateTime("@0"),
'extra' => array(),
'message' => 'log',
);
$wildfire->formatBatch(array($record));
}
}

@ -1,32 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
spl_autoload_register(function($class) {
$file = __DIR__.'/../../../../src/'.strtr($class, '\\', '/').'.php';
if (file_exists($file)) {
require $file;
return true;
}
});
use Monolog\Logger;
use Monolog\Handler\FirePHPHandler;
use Monolog\Handler\ChromePHPHandler;
$logger = new Logger('firephp');
$logger->pushHandler(new FirePHPHandler);
$logger->pushHandler(new ChromePHPHandler());
$logger->addDebug('Debug');
$logger->addInfo('Info');
$logger->addWarning('Warning');
$logger->addError('Error');

@ -1,104 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
use Monolog\Formatter\LineFormatter;
use Monolog\Processor\WebProcessor;
class AbstractHandlerTest extends TestCase
{
/**
* @covers Monolog\Handler\AbstractHandler::__construct
* @covers Monolog\Handler\AbstractHandler::getLevel
* @covers Monolog\Handler\AbstractHandler::setLevel
* @covers Monolog\Handler\AbstractHandler::getBubble
* @covers Monolog\Handler\AbstractHandler::setBubble
* @covers Monolog\Handler\AbstractHandler::getFormatter
* @covers Monolog\Handler\AbstractHandler::setFormatter
*/
public function testConstructAndGetSet()
{
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', array(Logger::WARNING, false));
$this->assertEquals(Logger::WARNING, $handler->getLevel());
$this->assertEquals(false, $handler->getBubble());
$handler->setLevel(Logger::ERROR);
$handler->setBubble(true);
$handler->setFormatter($formatter = new LineFormatter);
$this->assertEquals(Logger::ERROR, $handler->getLevel());
$this->assertEquals(true, $handler->getBubble());
$this->assertSame($formatter, $handler->getFormatter());
}
/**
* @covers Monolog\Handler\AbstractHandler::handleBatch
*/
public function testHandleBatch()
{
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler');
$handler->expects($this->exactly(2))
->method('handle');
$handler->handleBatch(array($this->getRecord(), $this->getRecord()));
}
/**
* @covers Monolog\Handler\AbstractHandler::isHandling
*/
public function testIsHandling()
{
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', array(Logger::WARNING, false));
$this->assertTrue($handler->isHandling($this->getRecord()));
$this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG)));
}
/**
* @covers Monolog\Handler\AbstractHandler::getFormatter
* @covers Monolog\Handler\AbstractHandler::getDefaultFormatter
*/
public function testGetFormatterInitializesDefault()
{
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler');
$this->assertInstanceOf('Monolog\Formatter\LineFormatter', $handler->getFormatter());
}
/**
* @covers Monolog\Handler\AbstractHandler::pushProcessor
* @covers Monolog\Handler\AbstractHandler::popProcessor
* @expectedException LogicException
*/
public function testPushPopProcessor()
{
$logger = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler');
$processor1 = new WebProcessor;
$processor2 = new WebProcessor;
$logger->pushProcessor($processor1);
$logger->pushProcessor($processor2);
$this->assertEquals($processor2, $logger->popProcessor());
$this->assertEquals($processor1, $logger->popProcessor());
$logger->popProcessor();
}
/**
* @covers Monolog\Handler\AbstractHandler::pushProcessor
* @expectedException InvalidArgumentException
*/
public function testPushProcessorWithNonCallable()
{
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler');
$handler->pushProcessor(new \stdClass());
}
}

@ -1,79 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
use Monolog\Processor\WebProcessor;
class AbstractProcessingHandlerTest extends TestCase
{
/**
* @covers Monolog\Handler\AbstractProcessingHandler::handle
*/
public function testHandleLowerLevelMessage()
{
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::WARNING, true));
$this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG)));
}
/**
* @covers Monolog\Handler\AbstractProcessingHandler::handle
*/
public function testHandleBubbling()
{
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::DEBUG, true));
$this->assertFalse($handler->handle($this->getRecord()));
}
/**
* @covers Monolog\Handler\AbstractProcessingHandler::handle
*/
public function testHandleNotBubbling()
{
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::DEBUG, false));
$this->assertTrue($handler->handle($this->getRecord()));
}
/**
* @covers Monolog\Handler\AbstractProcessingHandler::handle
*/
public function testHandleIsFalseWhenNotHandled()
{
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', array(Logger::WARNING, false));
$this->assertTrue($handler->handle($this->getRecord()));
$this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG)));
}
/**
* @covers Monolog\Handler\AbstractProcessingHandler::processRecord
*/
public function testProcessRecord()
{
$handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler');
$handler->pushProcessor(new WebProcessor(array(
'REQUEST_URI' => '',
'REQUEST_METHOD' => '',
'REMOTE_ADDR' => '',
'SERVER_NAME' => '',
)));
$handledRecord = null;
$handler->expects($this->once())
->method('write')
->will($this->returnCallback(function($record) use (&$handledRecord) {
$handledRecord = $record;
}))
;
$handler->handle($this->getRecord());
$this->assertEquals(5, count($handledRecord['extra']));
}
}

@ -1,38 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
class AmqpExchangeMock extends \AMQPExchange
{
protected $messages = array();
public function __construct()
{
}
public function publish($message, $routing_key, $params = 0, $attributes = array())
{
$this->messages[] = array($message, $routing_key, $params, $attributes);
return true;
}
public function getMessages()
{
return $this->messages;
}
public function setName($name)
{
return true;
}
}

@ -1,74 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
/**
* @covers Monolog\Handler\RotatingFileHandler
*/
class AmqpHandlerTest extends TestCase
{
public function setUp()
{
if (!class_exists('AMQPConnection') || !class_exists('AMQPExchange')) {
$this->markTestSkipped("amqp-php not installed");
}
if (!class_exists('AMQPChannel')) {
$this->markTestSkipped("Please update AMQP to version >= 1.0");
}
}
public function testHandle()
{
$exchange = $this->getExchange();
$handler = new AmqpHandler($exchange, 'log');
$record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
$expected = array(
array(
'message' => 'test',
'context' => array(
'data' => array(),
'foo' => 34,
),
'level' => 300,
'level_name' => 'WARNING',
'channel' => 'test',
'extra' => array(),
),
'warn.test',
0,
array(
'delivery_mode' => 2,
'Content-type' => 'application/json'
)
);
$handler->handle($record);
$messages = $exchange->getMessages();
$this->assertCount(1, $messages);
$messages[0][0] = json_decode($messages[0][0], true);
unset($messages[0][0]['datetime']);
$this->assertEquals($expected, $messages[0]);
}
protected function getExchange()
{
return new AmqpExchangeMock();
}
}

@ -1,149 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
class BufferHandlerTest extends TestCase
{
/**
* @covers Monolog\Handler\BufferHandler::__construct
* @covers Monolog\Handler\BufferHandler::handle
* @covers Monolog\Handler\BufferHandler::close
*/
public function testHandleBuffers()
{
$test = new TestHandler();
$handler = new BufferHandler($test);
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::INFO));
$this->assertFalse($test->hasDebugRecords());
$this->assertFalse($test->hasInfoRecords());
$handler->close();
$this->assertTrue($test->hasInfoRecords());
$this->assertTrue(count($test->getRecords()) === 2);
}
/**
* @covers Monolog\Handler\BufferHandler::close
* @covers Monolog\Handler\BufferHandler::flush
*/
public function testDestructPropagatesRecords()
{
$test = new TestHandler();
$handler = new BufferHandler($test);
$handler->handle($this->getRecord(Logger::WARNING));
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->__destruct();
$this->assertTrue($test->hasWarningRecords());
$this->assertTrue($test->hasDebugRecords());
}
/**
* @covers Monolog\Handler\BufferHandler::handle
*/
public function testHandleBufferLimit()
{
$test = new TestHandler();
$handler = new BufferHandler($test, 2);
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::INFO));
$handler->handle($this->getRecord(Logger::WARNING));
$handler->close();
$this->assertTrue($test->hasWarningRecords());
$this->assertTrue($test->hasInfoRecords());
$this->assertFalse($test->hasDebugRecords());
}
/**
* @covers Monolog\Handler\BufferHandler::handle
*/
public function testHandleBufferLimitWithFlushOnOverflow()
{
$test = new TestHandler();
$handler = new BufferHandler($test, 3, Logger::DEBUG, true, true);
// send two records
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::DEBUG));
$this->assertFalse($test->hasDebugRecords());
$this->assertCount(0, $test->getRecords());
// overflow
$handler->handle($this->getRecord(Logger::INFO));
$this->assertTrue($test->hasDebugRecords());
$this->assertCount(3, $test->getRecords());
// should buffer again
$handler->handle($this->getRecord(Logger::WARNING));
$this->assertCount(3, $test->getRecords());
$handler->close();
$this->assertCount(5, $test->getRecords());
$this->assertTrue($test->hasWarningRecords());
$this->assertTrue($test->hasInfoRecords());
}
/**
* @covers Monolog\Handler\BufferHandler::handle
*/
public function testHandleLevel()
{
$test = new TestHandler();
$handler = new BufferHandler($test, 0, Logger::INFO);
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::INFO));
$handler->handle($this->getRecord(Logger::WARNING));
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->close();
$this->assertTrue($test->hasWarningRecords());
$this->assertTrue($test->hasInfoRecords());
$this->assertFalse($test->hasDebugRecords());
}
/**
* @covers Monolog\Handler\BufferHandler::flush
*/
public function testFlush()
{
$test = new TestHandler();
$handler = new BufferHandler($test, 0);
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::INFO));
$handler->flush();
$this->assertTrue($test->hasInfoRecords());
$this->assertTrue($test->hasDebugRecords());
$this->assertFalse($test->hasWarningRecords());
}
/**
* @covers Monolog\Handler\BufferHandler::handle
*/
public function testHandleUsesProcessors()
{
$test = new TestHandler();
$handler = new BufferHandler($test);
$handler->pushProcessor(function ($record) {
$record['extra']['foo'] = true;
return $record;
});
$handler->handle($this->getRecord(Logger::WARNING));
$handler->flush();
$this->assertTrue($test->hasWarningRecords());
$records = $test->getRecords();
$this->assertTrue($records[0]['extra']['foo']);
}
}

@ -1,139 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
/**
* @covers Monolog\Handler\ChromePHPHandler
*/
class ChromePHPHandlerTest extends TestCase
{
protected function setUp()
{
TestChromePHPHandler::reset();
}
public function testHeaders()
{
$handler = new TestChromePHPHandler();
$handler->setFormatter($this->getIdentityFormatter());
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::WARNING));
$expected = array(
'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array(
'version' => ChromePHPHandler::VERSION,
'columns' => array('label', 'log', 'backtrace', 'type'),
'rows' => array(
'test',
'test',
),
'request_uri' => '',
))))
);
$this->assertEquals($expected, $handler->getHeaders());
}
public function testHeadersOverflow()
{
$handler = new TestChromePHPHandler();
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::WARNING, str_repeat('a', 150*1024)));
// overflow chrome headers limit
$handler->handle($this->getRecord(Logger::WARNING, str_repeat('a', 100*1024)));
$expected = array(
'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array(
'version' => ChromePHPHandler::VERSION,
'columns' => array('label', 'log', 'backtrace', 'type'),
'rows' => array(
array(
'test',
'test',
'unknown',
'log',
),
array(
'test',
str_repeat('a', 150*1024),
'unknown',
'warn',
),
array(
'monolog',
'Incomplete logs, chrome header size limit reached',
'unknown',
'warn',
),
),
'request_uri' => '',
))))
);
$this->assertEquals($expected, $handler->getHeaders());
}
public function testConcurrentHandlers()
{
$handler = new TestChromePHPHandler();
$handler->setFormatter($this->getIdentityFormatter());
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::WARNING));
$handler2 = new TestChromePHPHandler();
$handler2->setFormatter($this->getIdentityFormatter());
$handler2->handle($this->getRecord(Logger::DEBUG));
$handler2->handle($this->getRecord(Logger::WARNING));
$expected = array(
'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array(
'version' => ChromePHPHandler::VERSION,
'columns' => array('label', 'log', 'backtrace', 'type'),
'rows' => array(
'test',
'test',
'test',
'test',
),
'request_uri' => '',
))))
);
$this->assertEquals($expected, $handler2->getHeaders());
}
}
class TestChromePHPHandler extends ChromePHPHandler
{
protected $headers = array();
public static function reset()
{
self::$initialized = false;
self::$overflowed = false;
self::$json['rows'] = array();
}
protected function sendHeader($header, $content)
{
$this->headers[$header] = $content;
}
public function getHeaders()
{
return $this->headers;
}
}

@ -1,41 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
class CouchDBHandlerTest extends TestCase
{
public function testHandle()
{
$record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
$expected = array(
'message' => 'test',
'context' => array('data' => '[object] (stdClass: {})', 'foo' => 34),
'level' => Logger::WARNING,
'level_name' => 'WARNING',
'channel' => 'test',
'datetime' => $record['datetime']->format('Y-m-d H:i:s'),
'extra' => array(),
);
$handler = new CouchDBHandler();
try {
$handler->handle($record);
} catch (\RuntimeException $e) {
$this->markTestSkipped('Could not connect to couchdb server on http://localhost:5984');
}
}
}

@ -1,52 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
class DoctrineCouchDBHandlerTest extends TestCase
{
protected function setup()
{
if (!class_exists('Doctrine\CouchDB\CouchDBClient')) {
$this->markTestSkipped('The "doctrine/couchdb" package is not installed');
}
}
public function testHandle()
{
$client = $this->getMockBuilder('Doctrine\\CouchDB\\CouchDBClient')
->setMethods(array('postDocument'))
->disableOriginalConstructor()
->getMock();
$record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
$expected = array(
'message' => 'test',
'context' => array('data' => '[object] (stdClass: {})', 'foo' => 34),
'level' => Logger::WARNING,
'level_name' => 'WARNING',
'channel' => 'test',
'datetime' => $record['datetime']->format('Y-m-d H:i:s'),
'extra' => array(),
);
$client->expects($this->once())
->method('postDocument')
->with($expected);
$handler = new DoctrineCouchDBHandler($client);
$handler->handle($record);
}
}

@ -1,189 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
use Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy;
class FingersCrossedHandlerTest extends TestCase
{
/**
* @covers Monolog\Handler\FingersCrossedHandler::__construct
* @covers Monolog\Handler\FingersCrossedHandler::handle
*/
public function testHandleBuffers()
{
$test = new TestHandler();
$handler = new FingersCrossedHandler($test);
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::INFO));
$this->assertFalse($test->hasDebugRecords());
$this->assertFalse($test->hasInfoRecords());
$handler->handle($this->getRecord(Logger::WARNING));
$this->assertTrue($test->hasInfoRecords());
$this->assertTrue(count($test->getRecords()) === 3);
}
/**
* @covers Monolog\Handler\FingersCrossedHandler::handle
*/
public function testHandleStopsBufferingAfterTrigger()
{
$test = new TestHandler();
$handler = new FingersCrossedHandler($test);
$handler->handle($this->getRecord(Logger::WARNING));
$handler->handle($this->getRecord(Logger::DEBUG));
$this->assertTrue($test->hasWarningRecords());
$this->assertTrue($test->hasDebugRecords());
}
/**
* @covers Monolog\Handler\FingersCrossedHandler::handle
* @covers Monolog\Handler\FingersCrossedHandler::reset
*/
public function testHandleRestartBufferingAfterReset()
{
$test = new TestHandler();
$handler = new FingersCrossedHandler($test);
$handler->handle($this->getRecord(Logger::WARNING));
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->reset();
$handler->handle($this->getRecord(Logger::INFO));
$this->assertTrue($test->hasWarningRecords());
$this->assertTrue($test->hasDebugRecords());
$this->assertFalse($test->hasInfoRecords());
}
/**
* @covers Monolog\Handler\FingersCrossedHandler::handle
*/
public function testHandleRestartBufferingAfterBeingTriggeredWhenStopBufferingIsDisabled()
{
$test = new TestHandler();
$handler = new FingersCrossedHandler($test, Logger::WARNING, 0, false, false);
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::WARNING));
$handler->handle($this->getRecord(Logger::INFO));
$this->assertTrue($test->hasWarningRecords());
$this->assertTrue($test->hasDebugRecords());
$this->assertFalse($test->hasInfoRecords());
}
/**
* @covers Monolog\Handler\FingersCrossedHandler::handle
*/
public function testHandleBufferLimit()
{
$test = new TestHandler();
$handler = new FingersCrossedHandler($test, Logger::WARNING, 2);
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::INFO));
$handler->handle($this->getRecord(Logger::WARNING));
$this->assertTrue($test->hasWarningRecords());
$this->assertTrue($test->hasInfoRecords());
$this->assertFalse($test->hasDebugRecords());
}
/**
* @covers Monolog\Handler\FingersCrossedHandler::handle
*/
public function testHandleWithCallback()
{
$test = new TestHandler();
$handler = new FingersCrossedHandler(function($record, $handler) use ($test) {
return $test;
});
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::INFO));
$this->assertFalse($test->hasDebugRecords());
$this->assertFalse($test->hasInfoRecords());
$handler->handle($this->getRecord(Logger::WARNING));
$this->assertTrue($test->hasInfoRecords());
$this->assertTrue(count($test->getRecords()) === 3);
}
/**
* @covers Monolog\Handler\FingersCrossedHandler::handle
* @expectedException RuntimeException
*/
public function testHandleWithBadCallbackThrowsException()
{
$handler = new FingersCrossedHandler(function($record, $handler) {
return 'foo';
});
$handler->handle($this->getRecord(Logger::WARNING));
}
/**
* @covers Monolog\Handler\FingersCrossedHandler::isHandling
*/
public function testIsHandlingAlways()
{
$test = new TestHandler();
$handler = new FingersCrossedHandler($test, Logger::ERROR);
$this->assertTrue($handler->isHandling($this->getRecord(Logger::DEBUG)));
}
/**
* @covers Monolog\Handler\FingersCrossedHandler::__construct
* @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::__construct
* @covers Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy::isHandlerActivated
*/
public function testErrorLevelActivationStrategy()
{
$test = new TestHandler();
$handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING));
$handler->handle($this->getRecord(Logger::DEBUG));
$this->assertFalse($test->hasDebugRecords());
$handler->handle($this->getRecord(Logger::WARNING));
$this->assertTrue($test->hasDebugRecords());
$this->assertTrue($test->hasWarningRecords());
}
/**
* @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::__construct
* @covers Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy::isHandlerActivated
*/
public function testChannelLevelActivationStrategy()
{
$test = new TestHandler();
$handler = new FingersCrossedHandler($test, new ChannelLevelActivationStrategy(Logger::ERROR, array('othertest' => Logger::DEBUG)));
$handler->handle($this->getRecord(Logger::WARNING));
$this->assertFalse($test->hasWarningRecords());
$record = $this->getRecord(Logger::DEBUG);
$record['channel'] = 'othertest';
$handler->handle($record);
$this->assertTrue($test->hasDebugRecords());
$this->assertTrue($test->hasWarningRecords());
}
/**
* @covers Monolog\Handler\FingersCrossedHandler::handle
*/
public function testHandleUsesProcessors()
{
$test = new TestHandler();
$handler = new FingersCrossedHandler($test, Logger::INFO);
$handler->pushProcessor(function ($record) {
$record['extra']['foo'] = true;
return $record;
});
$handler->handle($this->getRecord(Logger::WARNING));
$this->assertTrue($test->hasWarningRecords());
$records = $test->getRecords();
$this->assertTrue($records[0]['extra']['foo']);
}
}

@ -1,94 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
/**
* @covers Monolog\Handler\FirePHPHandler
*/
class FirePHPHandlerTest extends TestCase
{
public function setUp()
{
TestFirePHPHandler::reset();
}
public function testHeaders()
{
$handler = new TestFirePHPHandler;
$handler->setFormatter($this->getIdentityFormatter());
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::WARNING));
$expected = array(
'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2',
'X-Wf-1-Structure-1' => 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1',
'X-Wf-1-Plugin-1' => 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3',
'X-Wf-1-1-1-1' => 'test',
'X-Wf-1-1-1-2' => 'test',
);
$this->assertEquals($expected, $handler->getHeaders());
}
public function testConcurrentHandlers()
{
$handler = new TestFirePHPHandler;
$handler->setFormatter($this->getIdentityFormatter());
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::WARNING));
$handler2 = new TestFirePHPHandler;
$handler2->setFormatter($this->getIdentityFormatter());
$handler2->handle($this->getRecord(Logger::DEBUG));
$handler2->handle($this->getRecord(Logger::WARNING));
$expected = array(
'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2',
'X-Wf-1-Structure-1' => 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1',
'X-Wf-1-Plugin-1' => 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3',
'X-Wf-1-1-1-1' => 'test',
'X-Wf-1-1-1-2' => 'test',
);
$expected2 = array(
'X-Wf-1-1-1-3' => 'test',
'X-Wf-1-1-1-4' => 'test',
);
$this->assertEquals($expected, $handler->getHeaders());
$this->assertEquals($expected2, $handler2->getHeaders());
}
}
class TestFirePHPHandler extends FirePHPHandler
{
protected $headers = array();
public static function reset()
{
self::$initialized = false;
self::$messageIndex = 1;
}
protected function sendHeader($header, $content)
{
$this->headers[$header] = $content;
}
public function getHeaders()
{
return $this->headers;
}
}

@ -1,94 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
use Monolog\Formatter\GelfMessageFormatter;
class GelfHandlerTest extends TestCase
{
public function setUp()
{
if (!class_exists("Gelf\MessagePublisher") || !class_exists("Gelf\Message")) {
$this->markTestSkipped("mlehner/gelf-php not installed");
}
require_once __DIR__ . '/GelfMocks.php';
}
/**
* @covers Monolog\Handler\GelfHandler::__construct
*/
public function testConstruct()
{
$handler = new GelfHandler($this->getMessagePublisher());
$this->assertInstanceOf('Monolog\Handler\GelfHandler', $handler);
}
protected function getHandler($messagePublisher)
{
$handler = new GelfHandler($messagePublisher);
return $handler;
}
protected function getMessagePublisher()
{
return new MockMessagePublisher('localhost');
}
public function testDebug()
{
$messagePublisher = $this->getMessagePublisher();
$handler = $this->getHandler($messagePublisher);
$record = $this->getRecord(Logger::DEBUG, "A test debug message");
$handler->handle($record);
$this->assertEquals(7, $messagePublisher->lastMessage->getLevel());
$this->assertEquals('test', $messagePublisher->lastMessage->getFacility());
$this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage());
$this->assertEquals(null, $messagePublisher->lastMessage->getFullMessage());
}
public function testWarning()
{
$messagePublisher = $this->getMessagePublisher();
$handler = $this->getHandler($messagePublisher);
$record = $this->getRecord(Logger::WARNING, "A test warning message");
$handler->handle($record);
$this->assertEquals(4, $messagePublisher->lastMessage->getLevel());
$this->assertEquals('test', $messagePublisher->lastMessage->getFacility());
$this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage());
$this->assertEquals(null, $messagePublisher->lastMessage->getFullMessage());
}
public function testInjectedGelfMessageFormatter()
{
$messagePublisher = $this->getMessagePublisher();
$handler = $this->getHandler($messagePublisher);
$handler->setFormatter(new GelfMessageFormatter('mysystem', 'EXT', 'CTX'));
$record = $this->getRecord(Logger::WARNING, "A test warning message");
$record['extra']['blarg'] = 'yep';
$record['context']['from'] = 'logger';
$handler->handle($record);
$this->assertEquals('mysystem', $messagePublisher->lastMessage->getHost());
$this->assertArrayHasKey('_EXTblarg', $messagePublisher->lastMessage->toArray());
$this->assertArrayHasKey('_CTXfrom', $messagePublisher->lastMessage->toArray());
}
}

@ -1,25 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Gelf\MessagePublisher;
use Gelf\Message;
class MockMessagePublisher extends MessagePublisher
{
public function publish(Message $message)
{
$this->lastMessage = $message;
}
public $lastMessage = null;
}

@ -1,89 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
class GroupHandlerTest extends TestCase
{
/**
* @covers Monolog\Handler\GroupHandler::__construct
* @expectedException InvalidArgumentException
*/
public function testConstructorOnlyTakesHandler()
{
new GroupHandler(array(new TestHandler(), "foo"));
}
/**
* @covers Monolog\Handler\GroupHandler::__construct
* @covers Monolog\Handler\GroupHandler::handle
*/
public function testHandle()
{
$testHandlers = array(new TestHandler(), new TestHandler());
$handler = new GroupHandler($testHandlers);
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::INFO));
foreach ($testHandlers as $test) {
$this->assertTrue($test->hasDebugRecords());
$this->assertTrue($test->hasInfoRecords());
$this->assertTrue(count($test->getRecords()) === 2);
}
}
/**
* @covers Monolog\Handler\GroupHandler::handleBatch
*/
public function testHandleBatch()
{
$testHandlers = array(new TestHandler(), new TestHandler());
$handler = new GroupHandler($testHandlers);
$handler->handleBatch(array($this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)));
foreach ($testHandlers as $test) {
$this->assertTrue($test->hasDebugRecords());
$this->assertTrue($test->hasInfoRecords());
$this->assertTrue(count($test->getRecords()) === 2);
}
}
/**
* @covers Monolog\Handler\GroupHandler::isHandling
*/
public function testIsHandling()
{
$testHandlers = array(new TestHandler(Logger::ERROR), new TestHandler(Logger::WARNING));
$handler = new GroupHandler($testHandlers);
$this->assertTrue($handler->isHandling($this->getRecord(Logger::ERROR)));
$this->assertTrue($handler->isHandling($this->getRecord(Logger::WARNING)));
$this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG)));
}
/**
* @covers Monolog\Handler\GroupHandler::handle
*/
public function testHandleUsesProcessors()
{
$test = new TestHandler();
$handler = new GroupHandler(array($test));
$handler->pushProcessor(function ($record) {
$record['extra']['foo'] = true;
return $record;
});
$handler->handle($this->getRecord(Logger::WARNING));
$this->assertTrue($test->hasWarningRecords());
$records = $test->getRecords();
$this->assertTrue($records[0]['extra']['foo']);
}
}

@ -1,110 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
/**
* @author Rafael Dohms <rafael@doh.ms>
* @see https://www.hipchat.com/docs/api
*/
class HipChatHandlerTest extends TestCase
{
private $res;
private $handler;
public function testWriteHeader()
{
$this->createHandler();
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
fseek($this->res, 0);
$content = fread($this->res, 1024);
$this->assertRegexp('/POST \/v1\/rooms\/message\?format=json&auth_token=.* HTTP\/1.1\\r\\nHost: api.hipchat.com\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
return $content;
}
/**
* @depends testWriteHeader
*/
public function testWriteContent($content)
{
$this->assertRegexp('/from=Monolog&room_id=room1&notify=0&message=test1&message_format=text&color=red$/', $content);
}
public function testWriteWithComplexMessage()
{
$this->createHandler();
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'Backup of database "example" finished in 16 minutes.'));
fseek($this->res, 0);
$content = fread($this->res, 1024);
$this->assertRegexp('/message=Backup\+of\+database\+%22example%22\+finished\+in\+16\+minutes\./', $content);
}
/**
* @dataProvider provideLevelColors
*/
public function testWriteWithErrorLevelsAndColors($level, $expectedColor)
{
$this->createHandler();
$this->handler->handle($this->getRecord($level, 'Backup of database "example" finished in 16 minutes.'));
fseek($this->res, 0);
$content = fread($this->res, 1024);
$this->assertRegexp('/color='.$expectedColor.'/', $content);
}
public function provideLevelColors()
{
return array(
array(Logger::DEBUG, 'gray'),
array(Logger::INFO, 'green'),
array(Logger::WARNING, 'yellow'),
array(Logger::ERROR, 'red'),
array(Logger::CRITICAL, 'red'),
array(Logger::ALERT, 'red'),
array(Logger::EMERGENCY,'red'),
array(Logger::NOTICE, 'green'),
);
}
private function createHandler($token = 'myToken', $room = 'room1', $name = 'Monolog', $notify = false)
{
$constructorArgs = array($token, $room, $name, $notify, Logger::DEBUG);
$this->res = fopen('php://memory', 'a');
$this->handler = $this->getMock(
'\Monolog\Handler\HipChatHandler',
array('fsockopen', 'streamSetTimeout', 'closeSocket'),
$constructorArgs
);
$reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($this->handler, 'localhost:1234');
$this->handler->expects($this->any())
->method('fsockopen')
->will($this->returnValue($this->res));
$this->handler->expects($this->any())
->method('streamSetTimeout')
->will($this->returnValue(true));
$this->handler->expects($this->any())
->method('closeSocket')
->will($this->returnValue(true));
$this->handler->setFormatter($this->getIdentityFormatter());
}
}

@ -1,75 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\TestCase;
class MailHandlerTest extends TestCase
{
/**
* @covers Monolog\Handler\MailHandler::handleBatch
*/
public function testHandleBatch()
{
$formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface');
$formatter->expects($this->once())
->method('formatBatch'); // Each record is formatted
$handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler');
$handler->expects($this->once())
->method('send');
$handler->expects($this->never())
->method('write'); // write is for individual records
$handler->setFormatter($formatter);
$handler->handleBatch($this->getMultipleRecords());
}
/**
* @covers Monolog\Handler\MailHandler::handleBatch
*/
public function testHandleBatchNotSendsMailIfMessagesAreBelowLevel()
{
$records = array(
$this->getRecord(Logger::DEBUG, 'debug message 1'),
$this->getRecord(Logger::DEBUG, 'debug message 2'),
$this->getRecord(Logger::INFO, 'information'),
);
$handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler');
$handler->expects($this->never())
->method('send');
$handler->setLevel(Logger::ERROR);
$handler->handleBatch($records);
}
/**
* @covers Monolog\Handler\MailHandler::write
*/
public function testHandle()
{
$handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler');
$record = $this->getRecord();
$records = array($record);
$records[0]['formatted'] = '['.$record['datetime']->format('Y-m-d H:i:s').'] test.WARNING: test [] []'."\n";
$handler->expects($this->once())
->method('send')
->with($records[0]['formatted'], $records);
$handler->handle($record);
}
}

@ -1,26 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Raven_Client;
class MockRavenClient extends Raven_Client
{
public function capture($data, $stack, $vars = null)
{
$this->lastData = $data;
$this->lastStack = $stack;
}
public $lastData;
public $lastStack;
}

@ -1,63 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
class MongoDBHandlerTest extends TestCase
{
/**
* @expectedException InvalidArgumentException
*/
public function testConstructorShouldThrowExceptionForInvalidMongo()
{
new MongoDBHandler(new \stdClass(), 'DB', 'Collection');
}
public function testHandle()
{
$mongo = $this->getMock('Mongo', array('selectCollection'));
$collection = $this->getMock('stdClass', array('save'));
$mongo->expects($this->once())
->method('selectCollection')
->with('DB', 'Collection')
->will($this->returnValue($collection));
$record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
$expected = array(
'message' => 'test',
'context' => array('data' => '[object] (stdClass: {})', 'foo' => 34),
'level' => Logger::WARNING,
'level_name' => 'WARNING',
'channel' => 'test',
'datetime' => $record['datetime']->format('Y-m-d H:i:s'),
'extra' => array(),
);
$collection->expects($this->once())
->method('save')
->with($expected);
$handler = new MongoDBHandler($mongo, 'DB', 'Collection');
$handler->handle($record);
}
}
if (!class_exists('Mongo')) {
class Mongo
{
public function selectCollection() {}
}
}

@ -1,43 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
class NativeMailerHandlerTest extends TestCase
{
/**
* @expectedException InvalidArgumentException
*/
public function testConstructorHeaderInjection()
{
$mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', "receiver@example.org\r\nFrom: faked@attacker.org");
}
/**
* @expectedException InvalidArgumentException
*/
public function testSetterHeaderInjection()
{
$mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org');
$mailer->addHeader("Content-Type: text/html\r\nFrom: faked@attacker.org");
}
/**
* @expectedException InvalidArgumentException
*/
public function testSetterArrayHeaderInjection()
{
$mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org');
$mailer->addHeader(array("Content-Type: text/html\r\nFrom: faked@attacker.org"));
}
}

@ -1,65 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
class NewRelicHandlerTest extends TestCase
{
/**
* @expectedException Monolog\Handler\MissingExtensionException
*/
public function testThehandlerThrowsAnExceptionIfTheNRExtensionIsNotLoaded()
{
$handler = new StubNewRelicHandlerWithoutExtension();
$handler->handle($this->getRecord(Logger::ERROR));
}
public function testThehandlerCanHandleTheRecord()
{
$handler = new StubNewRelicHandler();
$handler->handle($this->getRecord(Logger::ERROR));
}
public function testThehandlerCanAddParamsToTheNewRelicTrace()
{
$handler = new StubNewRelicHandler();
$handler->handle($this->getRecord(Logger::ERROR, 'log message', array('a' => 'b')));
}
}
class StubNewRelicHandlerWithoutExtension extends NewRelicHandler
{
protected function isNewRelicEnabled()
{
return false;
}
}
class StubNewRelicHandler extends NewRelicHandler
{
protected function isNewRelicEnabled()
{
return true;
}
}
function newrelic_notice_error()
{
return true;
}
function newrelic_add_custom_parameter()
{
return true;
}

@ -1,33 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
/**
* @covers Monolog\Handler\NullHandler::handle
*/
class NullHandlerTest extends TestCase
{
public function testHandle()
{
$handler = new NullHandler();
$this->assertTrue($handler->handle($this->getRecord()));
}
public function testHandleLowerLevelRecord()
{
$handler = new NullHandler(Logger::WARNING);
$this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG)));
}
}

@ -1,142 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
/**
* Almost all examples (expected header, titles, messages) taken from
* https://www.pushover.net/api
* @author Sebastian Göttschkes <sebastian.goettschkes@googlemail.com>
* @see https://www.pushover.net/api
*/
class PushoverHandlerTest extends TestCase
{
private $res;
private $handler;
public function testWriteHeader()
{
$this->createHandler();
$this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
fseek($this->res, 0);
$content = fread($this->res, 1024);
$this->assertRegexp('/POST \/1\/messages.json HTTP\/1.1\\r\\nHost: api.pushover.net\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content);
return $content;
}
/**
* @depends testWriteHeader
*/
public function testWriteContent($content)
{
$this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog&timestamp=\d{10}$/', $content);
}
public function testWriteWithComplexTitle()
{
$this->createHandler('myToken', 'myUser', 'Backup finished - SQL1', Logger::EMERGENCY);
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
fseek($this->res, 0);
$content = fread($this->res, 1024);
$this->assertRegexp('/title=Backup\+finished\+-\+SQL1/', $content);
}
public function testWriteWithComplexMessage()
{
$this->createHandler();
$this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'Backup of database "example" finished in 16 minutes.'));
fseek($this->res, 0);
$content = fread($this->res, 1024);
$this->assertRegexp('/message=Backup\+of\+database\+%22example%22\+finished\+in\+16\+minutes\./', $content);
}
public function testWriteWithTooLongMessage()
{
$message = str_pad('test', 520, 'a');
$this->createHandler();
$this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications
$this->handler->handle($this->getRecord(Logger::CRITICAL, $message));
fseek($this->res, 0);
$content = fread($this->res, 1024);
$expectedMessage = substr($message, 0, 505);
$this->assertRegexp('/message=' . $expectedMessage . '&title/', $content);
}
public function testWriteWithHighPriority()
{
$this->createHandler();
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1'));
fseek($this->res, 0);
$content = fread($this->res, 1024);
$this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog&timestamp=\d{10}&priority=1$/', $content);
}
public function testWriteWithEmergencyPriority()
{
$this->createHandler();
$this->handler->handle($this->getRecord(Logger::EMERGENCY, 'test1'));
fseek($this->res, 0);
$content = fread($this->res, 1024);
$this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog&timestamp=\d{10}&priority=2$/', $content);
}
public function testWriteToMultipleUsers()
{
$this->createHandler('myToken', array('userA', 'userB'));
$this->handler->handle($this->getRecord(Logger::EMERGENCY, 'test1'));
fseek($this->res, 0);
$content = fread($this->res, 1024);
$this->assertRegexp('/token=myToken&user=userA&message=test1&title=Monolog&timestamp=\d{10}&priority=2POST/', $content);
$this->assertRegexp('/token=myToken&user=userB&message=test1&title=Monolog&timestamp=\d{10}&priority=2$/', $content);
}
private function createHandler($token = 'myToken', $user = 'myUser', $title = 'Monolog')
{
$constructorArgs = array($token, $user, $title);
$this->res = fopen('php://memory', 'a');
$this->handler = $this->getMock(
'\Monolog\Handler\PushoverHandler',
array('fsockopen', 'streamSetTimeout', 'closeSocket'),
$constructorArgs
);
$reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($this->handler, 'localhost:1234');
$this->handler->expects($this->any())
->method('fsockopen')
->will($this->returnValue($this->res));
$this->handler->expects($this->any())
->method('streamSetTimeout')
->will($this->returnValue(true));
$this->handler->expects($this->any())
->method('closeSocket')
->will($this->returnValue(true));
$this->handler->setFormatter($this->getIdentityFormatter());
}
}

@ -1,135 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\RavenHandler;
class RavenHandlerTest extends TestCase
{
public function setUp()
{
if (!class_exists("Raven_Client")) {
$this->markTestSkipped("raven/raven not installed");
}
require_once __DIR__ . '/MockRavenClient.php';
}
/**
* @covers Monolog\Handler\RavenHandler::__construct
*/
public function testConstruct()
{
$handler = new RavenHandler($this->getRavenClient());
$this->assertInstanceOf('Monolog\Handler\RavenHandler', $handler);
}
protected function getHandler($ravenClient)
{
$handler = new RavenHandler($ravenClient);
return $handler;
}
protected function getRavenClient()
{
$dsn = 'http://43f6017361224d098402974103bfc53d:a6a0538fc2934ba2bed32e08741b2cd3@marca.python.live.cheggnet.com:9000/1';
return new MockRavenClient($dsn);
}
public function testDebug()
{
$ravenClient = $this->getRavenClient();
$handler = $this->getHandler($ravenClient);
$record = $this->getRecord(Logger::DEBUG, "A test debug message");
$handler->handle($record);
$this->assertEquals($ravenClient::DEBUG, $ravenClient->lastData['level']);
$this->assertContains($record['message'], $ravenClient->lastData['message']);
}
public function testWarning()
{
$ravenClient = $this->getRavenClient();
$handler = $this->getHandler($ravenClient);
$record = $this->getRecord(Logger::WARNING, "A test warning message");
$handler->handle($record);
$this->assertEquals($ravenClient::WARNING, $ravenClient->lastData['level']);
$this->assertContains($record['message'], $ravenClient->lastData['message']);
}
public function testException()
{
$ravenClient = $this->getRavenClient();
$handler = $this->getHandler($ravenClient);
try {
$this->methodThatThrowsAnException();
} catch (\Exception $e) {
$record = $this->getRecord(Logger::ERROR, $e->getMessage(), array('exception' => $e));
$handler->handle($record);
}
$this->assertEquals($record['message'], $ravenClient->lastData['message']);
}
public function testHandleBatch()
{
$records = $this->getMultipleRecords();
$logFormatter = $this->getMock('Monolog\\Formatter\\FormatterInterface');
$logFormatter->expects($this->once())->method('formatBatch');
$formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface');
$formatter->expects($this->once())->method('format');
$handler = $this->getHandler($this->getRavenClient());
$handler->setBatchFormatter($logFormatter);
$handler->setFormatter($formatter);
$handler->handleBatch($records);
}
public function testHandleBatchDoNothingIfRecordsAreBelowLevel()
{
$records = array(
$this->getRecord(Logger::DEBUG, 'debug message 1'),
$this->getRecord(Logger::DEBUG, 'debug message 2'),
$this->getRecord(Logger::INFO, 'information'),
);
$handler = $this->getMock('Monolog\Handler\RavenHandler', null, array($this->getRavenClient()));
$handler->expects($this->never())->method('handle');
$handler->setLevel(Logger::ERROR);
$handler->handleBatch($records);
}
public function testGetSetBatchFormatter()
{
$ravenClient = $this->getRavenClient();
$handler = $this->getHandler($ravenClient);
$handler->setBatchFormatter($formatter = new LineFormatter());
$this->assertSame($formatter, $handler->getBatchFormatter());
}
private function methodThatThrowsAnException()
{
throw new \Exception('This is an exception');
}
}

@ -1,71 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
use Monolog\Formatter\LineFormatter;
class RedisHandlerTest extends TestCase
{
/**
* @expectedException InvalidArgumentException
*/
public function testConstructorShouldThrowExceptionForInvalidRedis()
{
new RedisHandler(new \stdClass(), 'key');
}
public function testConstructorShouldWorkWithPredis()
{
$redis = $this->getMock('Predis\Client');
$this->assertInstanceof('Monolog\Handler\RedisHandler', new RedisHandler($redis, 'key'));
}
public function testConstructorShouldWorkWithRedis()
{
$redis = $this->getMock('Redis');
$this->assertInstanceof('Monolog\Handler\RedisHandler', new RedisHandler($redis, 'key'));
}
public function testPredisHandle()
{
$redis = $this->getMock('Predis\Client', array('rpush'));
// Predis\Client uses rpush
$redis->expects($this->once())
->method('rpush')
->with('key', 'test');
$record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
$handler = new RedisHandler($redis, 'key');
$handler->setFormatter(new LineFormatter("%message%"));
$handler->handle($record);
}
public function testRedisHandle()
{
$redis = $this->getMock('Redis', array('rpush'));
// Redis uses rPush
$redis->expects($this->once())
->method('rPush')
->with('key', 'test');
$record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34));
$handler = new RedisHandler($redis, 'key');
$handler->setFormatter(new LineFormatter("%message%"));
$handler->handle($record);
}
}

@ -1,99 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
/**
* @covers Monolog\Handler\RotatingFileHandler
*/
class RotatingFileHandlerTest extends TestCase
{
public function setUp()
{
$dir = __DIR__.'/Fixtures';
chmod($dir, 0777);
if (!is_writable($dir)) {
$this->markTestSkipped($dir.' must be writeable to test the RotatingFileHandler.');
}
}
public function testRotationCreatesNewFile()
{
touch(__DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400).'.rot');
$handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot');
$handler->setFormatter($this->getIdentityFormatter());
$handler->handle($this->getRecord());
$log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot';
$this->assertTrue(file_exists($log));
$this->assertEquals('test', file_get_contents($log));
}
/**
* @dataProvider rotationTests
*/
public function testRotation($createFile)
{
touch($old1 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400).'.rot');
touch($old2 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400 * 2).'.rot');
touch($old3 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400 * 3).'.rot');
touch($old4 = __DIR__.'/Fixtures/foo-'.date('Y-m-d', time() - 86400 * 4).'.rot');
$log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot';
if ($createFile) {
touch($log);
}
$handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot', 2);
$handler->setFormatter($this->getIdentityFormatter());
$handler->handle($this->getRecord());
$handler->close();
$this->assertTrue(file_exists($log));
$this->assertTrue(file_exists($old1));
$this->assertEquals($createFile, file_exists($old2));
$this->assertEquals($createFile, file_exists($old3));
$this->assertEquals($createFile, file_exists($old4));
$this->assertEquals('test', file_get_contents($log));
}
public function rotationTests()
{
return array(
'Rotation is triggered when the file of the current day is not present'
=> array(true),
'Rotation is not triggered when the file is already present'
=> array(false),
);
}
public function testReuseCurrentFile()
{
$log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot';
file_put_contents($log, "foo");
$handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot');
$handler->setFormatter($this->getIdentityFormatter());
$handler->handle($this->getRecord());
$this->assertEquals('footest', file_get_contents($log));
}
public function tearDown()
{
foreach (glob(__DIR__.'/Fixtures/*.rot') as $file) {
unlink($file);
}
}
}

@ -1,283 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
/**
* @author Pablo de Leon Belloc <pablolb@gmail.com>
*/
class SocketHandlerTest extends TestCase
{
/**
* @var Monolog\Handler\SocketHandler
*/
private $handler;
/**
* @var resource
*/
private $res;
/**
* @expectedException UnexpectedValueException
*/
public function testInvalidHostname()
{
$this->createHandler('garbage://here');
$this->writeRecord('data');
}
/**
* @expectedException \InvalidArgumentException
*/
public function testBadConnectionTimeout()
{
$this->createHandler('localhost:1234');
$this->handler->setConnectionTimeout(-1);
}
public function testSetConnectionTimeout()
{
$this->createHandler('localhost:1234');
$this->handler->setConnectionTimeout(10.1);
$this->assertEquals(10.1, $this->handler->getConnectionTimeout());
}
/**
* @expectedException \InvalidArgumentException
*/
public function testBadTimeout()
{
$this->createHandler('localhost:1234');
$this->handler->setTimeout(-1);
}
public function testSetTimeout()
{
$this->createHandler('localhost:1234');
$this->handler->setTimeout(10.25);
$this->assertEquals(10.25, $this->handler->getTimeout());
}
public function testSetConnectionString()
{
$this->createHandler('tcp://localhost:9090');
$this->assertEquals('tcp://localhost:9090', $this->handler->getConnectionString());
}
/**
* @expectedException UnexpectedValueException
*/
public function testExceptionIsThrownOnFsockopenError()
{
$this->setMockHandler(array('fsockopen'));
$this->handler->expects($this->once())
->method('fsockopen')
->will($this->returnValue(false));
$this->writeRecord('Hello world');
}
/**
* @expectedException UnexpectedValueException
*/
public function testExceptionIsThrownOnPfsockopenError()
{
$this->setMockHandler(array('pfsockopen'));
$this->handler->expects($this->once())
->method('pfsockopen')
->will($this->returnValue(false));
$this->handler->setPersistent(true);
$this->writeRecord('Hello world');
}
/**
* @expectedException UnexpectedValueException
*/
public function testExceptionIsThrownIfCannotSetTimeout()
{
$this->setMockHandler(array('streamSetTimeout'));
$this->handler->expects($this->once())
->method('streamSetTimeout')
->will($this->returnValue(false));
$this->writeRecord('Hello world');
}
/**
* @expectedException RuntimeException
*/
public function testWriteFailsOnIfFwriteReturnsFalse()
{
$this->setMockHandler(array('fwrite'));
$callback = function($arg) {
$map = array(
'Hello world' => 6,
'world' => false,
);
return $map[$arg];
};
$this->handler->expects($this->exactly(2))
->method('fwrite')
->will($this->returnCallback($callback));
$this->writeRecord('Hello world');
}
/**
* @expectedException RuntimeException
*/
public function testWriteFailsIfStreamTimesOut()
{
$this->setMockHandler(array('fwrite', 'streamGetMetadata'));
$callback = function($arg) {
$map = array(
'Hello world' => 6,
'world' => 5,
);
return $map[$arg];
};
$this->handler->expects($this->exactly(1))
->method('fwrite')
->will($this->returnCallback($callback));
$this->handler->expects($this->exactly(1))
->method('streamGetMetadata')
->will($this->returnValue(array('timed_out' => true)));
$this->writeRecord('Hello world');
}
/**
* @expectedException RuntimeException
*/
public function testWriteFailsOnIncompleteWrite()
{
$this->setMockHandler(array('fwrite', 'streamGetMetadata'));
$res = $this->res;
$callback = function($string) use ($res) {
fclose($res);
return strlen('Hello');
};
$this->handler->expects($this->exactly(1))
->method('fwrite')
->will($this->returnCallback($callback));
$this->handler->expects($this->exactly(1))
->method('streamGetMetadata')
->will($this->returnValue(array('timed_out' => false)));
$this->writeRecord('Hello world');
}
public function testWriteWithMemoryFile()
{
$this->setMockHandler();
$this->writeRecord('test1');
$this->writeRecord('test2');
$this->writeRecord('test3');
fseek($this->res, 0);
$this->assertEquals('test1test2test3', fread($this->res, 1024));
}
public function testWriteWithMock()
{
$this->setMockHandler(array('fwrite'));
$callback = function($arg) {
$map = array(
'Hello world' => 6,
'world' => 5,
);
return $map[$arg];
};
$this->handler->expects($this->exactly(2))
->method('fwrite')
->will($this->returnCallback($callback));
$this->writeRecord('Hello world');
}
public function testClose()
{
$this->setMockHandler();
$this->writeRecord('Hello world');
$this->assertInternalType('resource', $this->res);
$this->handler->close();
$this->assertFalse(is_resource($this->res), "Expected resource to be closed after closing handler");
}
public function testCloseDoesNotClosePersistentSocket()
{
$this->setMockHandler();
$this->handler->setPersistent(true);
$this->writeRecord('Hello world');
$this->assertTrue(is_resource($this->res));
$this->handler->close();
$this->assertTrue(is_resource($this->res));
}
private function createHandler($connectionString)
{
$this->handler = new SocketHandler($connectionString);
$this->handler->setFormatter($this->getIdentityFormatter());
}
private function writeRecord($string)
{
$this->handler->handle($this->getRecord(Logger::WARNING, $string));
}
private function setMockHandler(array $methods = array())
{
$this->res = fopen('php://memory', 'a');
$defaultMethods = array('fsockopen', 'pfsockopen', 'streamSetTimeout');
$newMethods = array_diff($methods, $defaultMethods);
$finalMethods = array_merge($defaultMethods, $newMethods);
$this->handler = $this->getMock(
'\Monolog\Handler\SocketHandler', $finalMethods, array('localhost:1234')
);
if (!in_array('fsockopen', $methods)) {
$this->handler->expects($this->any())
->method('fsockopen')
->will($this->returnValue($this->res));
}
if (!in_array('pfsockopen', $methods)) {
$this->handler->expects($this->any())
->method('pfsockopen')
->will($this->returnValue($this->res));
}
if (!in_array('streamSetTimeout', $methods)) {
$this->handler->expects($this->any())
->method('streamSetTimeout')
->will($this->returnValue(true));
}
$this->handler->setFormatter($this->getIdentityFormatter());
}
}

@ -1,88 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
class StreamHandlerTest extends TestCase
{
/**
* @covers Monolog\Handler\StreamHandler::__construct
* @covers Monolog\Handler\StreamHandler::write
*/
public function testWrite()
{
$handle = fopen('php://memory', 'a+');
$handler = new StreamHandler($handle);
$handler->setFormatter($this->getIdentityFormatter());
$handler->handle($this->getRecord(Logger::WARNING, 'test'));
$handler->handle($this->getRecord(Logger::WARNING, 'test2'));
$handler->handle($this->getRecord(Logger::WARNING, 'test3'));
fseek($handle, 0);
$this->assertEquals('testtest2test3', fread($handle, 100));
}
/**
* @covers Monolog\Handler\StreamHandler::close
*/
public function testClose()
{
$handle = fopen('php://memory', 'a+');
$handler = new StreamHandler($handle);
$this->assertTrue(is_resource($handle));
$handler->close();
$this->assertFalse(is_resource($handle));
}
/**
* @covers Monolog\Handler\StreamHandler::write
*/
public function testWriteCreatesTheStreamResource()
{
$handler = new StreamHandler('php://memory');
$handler->handle($this->getRecord());
}
/**
* @expectedException LogicException
* @covers Monolog\Handler\StreamHandler::__construct
* @covers Monolog\Handler\StreamHandler::write
*/
public function testWriteMissingResource()
{
$handler = new StreamHandler(null);
$handler->handle($this->getRecord());
}
/**
* @expectedException UnexpectedValueException
* @covers Monolog\Handler\StreamHandler::__construct
* @covers Monolog\Handler\StreamHandler::write
*/
public function testWriteInvalidResource()
{
$handler = new StreamHandler('bogus://url');
$handler->handle($this->getRecord());
}
/**
* @expectedException UnexpectedValueException
* @covers Monolog\Handler\StreamHandler::__construct
* @covers Monolog\Handler\StreamHandler::write
*/
public function testWriteNonExistingResource()
{
$handler = new StreamHandler('/foo/bar/baz/'.rand(0, 10000));
$handler->handle($this->getRecord());
}
}

@ -1,43 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
class SyslogHandlerTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers Monolog\Handler\SyslogHandler::__construct
*/
public function testConstruct()
{
$handler = new SyslogHandler('test');
$this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler);
$handler = new SyslogHandler('test', LOG_USER);
$this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler);
$handler = new SyslogHandler('test', 'user');
$this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler);
$handler = new SyslogHandler('test', LOG_USER, Logger::DEBUG, true, LOG_PERROR);
$this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler);
}
/**
* @covers Monolog\Handler\SyslogHandler::__construct
*/
public function testConstructInvalidFacility()
{
$this->setExpectedException('UnexpectedValueException');
$handler = new SyslogHandler('test', 'unknown');
}
}

@ -1,56 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
/**
* @covers Monolog\Handler\TestHandler
*/
class TestHandlerTest extends TestCase
{
/**
* @dataProvider methodProvider
*/
public function testHandler($method, $level)
{
$handler = new TestHandler;
$record = $this->getRecord($level, 'test'.$method);
$this->assertFalse($handler->{'has'.$method}($record));
$this->assertFalse($handler->{'has'.$method.'Records'}());
$handler->handle($record);
$this->assertFalse($handler->{'has'.$method}('bar'));
$this->assertTrue($handler->{'has'.$method}($record));
$this->assertTrue($handler->{'has'.$method}('test'.$method));
$this->assertTrue($handler->{'has'.$method.'Records'}());
$records = $handler->getRecords();
unset($records[0]['formatted']);
$this->assertEquals(array($record), $records);
}
public function methodProvider()
{
return array(
array('Emergency', Logger::EMERGENCY),
array('Alert' , Logger::ALERT),
array('Critical' , Logger::CRITICAL),
array('Error' , Logger::ERROR),
array('Warning' , Logger::WARNING),
array('Info' , Logger::INFO),
array('Notice' , Logger::NOTICE),
array('Debug' , Logger::DEBUG),
);
}
}

@ -1,69 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
class ZendMonitorHandlerTest extends TestCase
{
protected $zendMonitorHandler;
public function setUp()
{
if (!function_exists('zend_monitor_custom_event')) {
$this->markTestSkipped('ZendServer is not installed');
}
}
/**
* @covers Monolog\Handler\ZendMonitorHandler::write
*/
public function testWrite()
{
$record = $this->getRecord();
$formatterResult = array(
'message' => $record['message']
);
$zendMonitor = $this->getMockBuilder('Monolog\Handler\ZendMonitorHandler')
->setMethods(array('writeZendMonitorCustomEvent', 'getDefaultFormatter'))
->getMock();
$formatterMock = $this->getMockBuilder('Monolog\Formatter\NormalizerFormatter')
->disableOriginalConstructor()
->getMock();
$formatterMock->expects($this->once())
->method('format')
->will($this->returnValue($formatterResult));
$zendMonitor->expects($this->once())
->method('getDefaultFormatter')
->will($this->returnValue($formatterMock));
$levelMap = $zendMonitor->getLevelMap();
$zendMonitor->expects($this->once())
->method('writeZendMonitorCustomEvent')
->with($levelMap[$record['level']], $record['message'], $formatterResult);
$zendMonitor->handle($record);
}
/**
* @covers Monolog\Handler\ZendMonitorHandler::getDefaultFormatter
*/
public function testGetDefaultFormatterReturnsNormalizerFormatter()
{
$zendMonitor = new ZendMonitorHandler();
$this->assertInstanceOf('Monolog\Formatter\NormalizerFormatter', $zendMonitor->getDefaultFormatter());
}
}

@ -1,409 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog;
use Monolog\Processor\WebProcessor;
use Monolog\Handler\TestHandler;
class LoggerTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers Monolog\Logger::getName
*/
public function testGetName()
{
$logger = new Logger('foo');
$this->assertEquals('foo', $logger->getName());
}
/**
* @covers Monolog\Logger::getLevelName
*/
public function testGetLevelName()
{
$this->assertEquals('ERROR', Logger::getLevelName(Logger::ERROR));
}
/**
* @covers Monolog\Logger::getLevelName
* @expectedException InvalidArgumentException
*/
public function testGetLevelNameThrows()
{
Logger::getLevelName(5);
}
/**
* @covers Monolog\Logger::__construct
*/
public function testChannel()
{
$logger = new Logger('foo');
$handler = new TestHandler;
$logger->pushHandler($handler);
$logger->addWarning('test');
list($record) = $handler->getRecords();
$this->assertEquals('foo', $record['channel']);
}
/**
* @covers Monolog\Logger::addRecord
*/
public function testLog()
{
$logger = new Logger(__METHOD__);
$handler = $this->getMock('Monolog\Handler\NullHandler', array('handle'));
$handler->expects($this->once())
->method('handle');
$logger->pushHandler($handler);
$this->assertTrue($logger->addWarning('test'));
}
/**
* @covers Monolog\Logger::addRecord
*/
public function testLogNotHandled()
{
$logger = new Logger(__METHOD__);
$handler = $this->getMock('Monolog\Handler\NullHandler', array('handle'), array(Logger::ERROR));
$handler->expects($this->never())
->method('handle');
$logger->pushHandler($handler);
$this->assertFalse($logger->addWarning('test'));
}
public function testHandlersInCtor()
{
$handler1 = new TestHandler;
$handler2 = new TestHandler;
$logger = new Logger(__METHOD__, array($handler1, $handler2));
$this->assertEquals($handler1, $logger->popHandler());
$this->assertEquals($handler2, $logger->popHandler());
}
public function testProcessorsInCtor()
{
$processor1 = new WebProcessor;
$processor2 = new WebProcessor;
$logger = new Logger(__METHOD__, array(), array($processor1, $processor2));
$this->assertEquals($processor1, $logger->popProcessor());
$this->assertEquals($processor2, $logger->popProcessor());
}
/**
* @covers Monolog\Logger::pushHandler
* @covers Monolog\Logger::popHandler
* @expectedException LogicException
*/
public function testPushPopHandler()
{
$logger = new Logger(__METHOD__);
$handler1 = new TestHandler;
$handler2 = new TestHandler;
$logger->pushHandler($handler1);
$logger->pushHandler($handler2);
$this->assertEquals($handler2, $logger->popHandler());
$this->assertEquals($handler1, $logger->popHandler());
$logger->popHandler();
}
/**
* @covers Monolog\Logger::pushProcessor
* @covers Monolog\Logger::popProcessor
* @expectedException LogicException
*/
public function testPushPopProcessor()
{
$logger = new Logger(__METHOD__);
$processor1 = new WebProcessor;
$processor2 = new WebProcessor;
$logger->pushProcessor($processor1);
$logger->pushProcessor($processor2);
$this->assertEquals($processor2, $logger->popProcessor());
$this->assertEquals($processor1, $logger->popProcessor());
$logger->popProcessor();
}
/**
* @covers Monolog\Logger::pushProcessor
* @expectedException InvalidArgumentException
*/
public function testPushProcessorWithNonCallable()
{
$logger = new Logger(__METHOD__);
$logger->pushProcessor(new \stdClass());
}
/**
* @covers Monolog\Logger::addRecord
*/
public function testProcessorsAreExecuted()
{
$logger = new Logger(__METHOD__);
$handler = new TestHandler;
$logger->pushHandler($handler);
$logger->pushProcessor(function($record) {
$record['extra']['win'] = true;
return $record;
});
$logger->addError('test');
list($record) = $handler->getRecords();
$this->assertTrue($record['extra']['win']);
}
/**
* @covers Monolog\Logger::addRecord
*/
public function testProcessorsAreCalledOnlyOnce()
{
$logger = new Logger(__METHOD__);
$handler = $this->getMock('Monolog\Handler\HandlerInterface');
$handler->expects($this->any())
->method('isHandling')
->will($this->returnValue(true))
;
$handler->expects($this->any())
->method('handle')
->will($this->returnValue(true))
;
$logger->pushHandler($handler);
$processor = $this->getMockBuilder('Monolog\Processor\WebProcessor')
->disableOriginalConstructor()
->setMethods(array('__invoke'))
->getMock()
;
$processor->expects($this->once())
->method('__invoke')
->will($this->returnArgument(0))
;
$logger->pushProcessor($processor);
$logger->addError('test');
}
/**
* @covers Monolog\Logger::addRecord
*/
public function testProcessorsNotCalledWhenNotHandled()
{
$logger = new Logger(__METHOD__);
$handler = $this->getMock('Monolog\Handler\HandlerInterface');
$handler->expects($this->once())
->method('isHandling')
->will($this->returnValue(false))
;
$logger->pushHandler($handler);
$that = $this;
$logger->pushProcessor(function($record) use ($that) {
$that->fail('The processor should not be called');
});
$logger->addAlert('test');
}
/**
* @covers Monolog\Logger::addRecord
*/
public function testHandlersNotCalledBeforeFirstHandling()
{
$logger = new Logger(__METHOD__);
$handler1 = $this->getMock('Monolog\Handler\HandlerInterface');
$handler1->expects($this->never())
->method('isHandling')
->will($this->returnValue(false))
;
$handler1->expects($this->once())
->method('handle')
->will($this->returnValue(false))
;
$logger->pushHandler($handler1);
$handler2 = $this->getMock('Monolog\Handler\HandlerInterface');
$handler2->expects($this->once())
->method('isHandling')
->will($this->returnValue(true))
;
$handler2->expects($this->once())
->method('handle')
->will($this->returnValue(false))
;
$logger->pushHandler($handler2);
$handler3 = $this->getMock('Monolog\Handler\HandlerInterface');
$handler3->expects($this->once())
->method('isHandling')
->will($this->returnValue(false))
;
$handler3->expects($this->never())
->method('handle')
;
$logger->pushHandler($handler3);
$logger->debug('test');
}
/**
* @covers Monolog\Logger::addRecord
*/
public function testBubblingWhenTheHandlerReturnsFalse()
{
$logger = new Logger(__METHOD__);
$handler1 = $this->getMock('Monolog\Handler\HandlerInterface');
$handler1->expects($this->any())
->method('isHandling')
->will($this->returnValue(true))
;
$handler1->expects($this->once())
->method('handle')
->will($this->returnValue(false))
;
$logger->pushHandler($handler1);
$handler2 = $this->getMock('Monolog\Handler\HandlerInterface');
$handler2->expects($this->any())
->method('isHandling')
->will($this->returnValue(true))
;
$handler2->expects($this->once())
->method('handle')
->will($this->returnValue(false))
;
$logger->pushHandler($handler2);
$logger->debug('test');
}
/**
* @covers Monolog\Logger::addRecord
*/
public function testNotBubblingWhenTheHandlerReturnsTrue()
{
$logger = new Logger(__METHOD__);
$handler1 = $this->getMock('Monolog\Handler\HandlerInterface');
$handler1->expects($this->any())
->method('isHandling')
->will($this->returnValue(true))
;
$handler1->expects($this->never())
->method('handle')
;
$logger->pushHandler($handler1);
$handler2 = $this->getMock('Monolog\Handler\HandlerInterface');
$handler2->expects($this->any())
->method('isHandling')
->will($this->returnValue(true))
;
$handler2->expects($this->once())
->method('handle')
->will($this->returnValue(true))
;
$logger->pushHandler($handler2);
$logger->debug('test');
}
/**
* @covers Monolog\Logger::isHandling
*/
public function testIsHandling()
{
$logger = new Logger(__METHOD__);
$handler1 = $this->getMock('Monolog\Handler\HandlerInterface');
$handler1->expects($this->any())
->method('isHandling')
->will($this->returnValue(false))
;
$logger->pushHandler($handler1);
$this->assertFalse($logger->isHandling(Logger::DEBUG));
$handler2 = $this->getMock('Monolog\Handler\HandlerInterface');
$handler2->expects($this->any())
->method('isHandling')
->will($this->returnValue(true))
;
$logger->pushHandler($handler2);
$this->assertTrue($logger->isHandling(Logger::DEBUG));
}
/**
* @dataProvider logMethodProvider
* @covers Monolog\Logger::addDebug
* @covers Monolog\Logger::addInfo
* @covers Monolog\Logger::addNotice
* @covers Monolog\Logger::addWarning
* @covers Monolog\Logger::addError
* @covers Monolog\Logger::addCritical
* @covers Monolog\Logger::addAlert
* @covers Monolog\Logger::addEmergency
* @covers Monolog\Logger::debug
* @covers Monolog\Logger::info
* @covers Monolog\Logger::notice
* @covers Monolog\Logger::warn
* @covers Monolog\Logger::err
* @covers Monolog\Logger::crit
* @covers Monolog\Logger::alert
* @covers Monolog\Logger::emerg
*/
public function testLogMethods($method, $expectedLevel)
{
$logger = new Logger('foo');
$handler = new TestHandler;
$logger->pushHandler($handler);
$logger->{$method}('test');
list($record) = $handler->getRecords();
$this->assertEquals($expectedLevel, $record['level']);
}
public function logMethodProvider()
{
return array(
// monolog methods
array('addDebug', Logger::DEBUG),
array('addInfo', Logger::INFO),
array('addNotice', Logger::NOTICE),
array('addWarning', Logger::WARNING),
array('addError', Logger::ERROR),
array('addCritical', Logger::CRITICAL),
array('addAlert', Logger::ALERT),
array('addEmergency', Logger::EMERGENCY),
// ZF/Sf2 compat methods
array('debug', Logger::DEBUG),
array('info', Logger::INFO),
array('notice', Logger::NOTICE),
array('warn', Logger::WARNING),
array('err', Logger::ERROR),
array('crit', Logger::CRITICAL),
array('alert', Logger::ALERT),
array('emerg', Logger::EMERGENCY),
);
}
}

@ -1,65 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Processor;
use Monolog\TestCase;
use Monolog\Handler\TestHandler;
class IntrospectionProcessorTest extends TestCase
{
public function getHandler()
{
$processor = new IntrospectionProcessor();
$handler = new TestHandler();
$handler->pushProcessor($processor);
return $handler;
}
public function testProcessorFromClass()
{
$handler = $this->getHandler();
$tester = new \Acme\Tester;
$tester->test($handler, $this->getRecord());
list($record) = $handler->getRecords();
$this->assertEquals(__FILE__, $record['extra']['file']);
$this->assertEquals(58, $record['extra']['line']);
$this->assertEquals('Acme\Tester', $record['extra']['class']);
$this->assertEquals('test', $record['extra']['function']);
}
public function testProcessorFromFunc()
{
$handler = $this->getHandler();
\Acme\tester($handler, $this->getRecord());
list($record) = $handler->getRecords();
$this->assertEquals(__FILE__, $record['extra']['file']);
$this->assertEquals(64, $record['extra']['line']);
$this->assertEquals(null, $record['extra']['class']);
$this->assertEquals('Acme\tester', $record['extra']['function']);
}
}
namespace Acme;
class Tester
{
public function test($handler, $record)
{
$handler->handle($record);
}
}
function tester($handler, $record)
{
$handler->handle($record);
}

@ -1,29 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Processor;
use Monolog\TestCase;
class MemoryPeakUsageProcessorTest extends TestCase
{
/**
* @covers Monolog\Processor\MemoryPeakUsageProcessor::__invoke
* @covers Monolog\Processor\MemoryProcessor::formatBytes
*/
public function testProcessor()
{
$processor = new MemoryPeakUsageProcessor();
$record = $processor($this->getRecord());
$this->assertArrayHasKey('memory_peak_usage', $record['extra']);
$this->assertRegExp('#[0-9.]+ (M|K)?B$#', $record['extra']['memory_peak_usage']);
}
}

@ -1,29 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Processor;
use Monolog\TestCase;
class MemoryUsageProcessorTest extends TestCase
{
/**
* @covers Monolog\Processor\MemoryUsageProcessor::__invoke
* @covers Monolog\Processor\MemoryProcessor::formatBytes
*/
public function testProcessor()
{
$processor = new MemoryUsageProcessor();
$record = $processor($this->getRecord());
$this->assertArrayHasKey('memory_usage', $record['extra']);
$this->assertRegExp('#[0-9.]+ (M|K)?B$#', $record['extra']['memory_usage']);
}
}

@ -1,30 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Processor;
use Monolog\TestCase;
class ProcessIdProcessorTest extends TestCase
{
/**
* @covers Monolog\Processor\ProcessIdProcessor::__invoke
*/
public function testProcessor()
{
$processor = new ProcessIdProcessor();
$record = $processor($this->getRecord());
$this->assertArrayHasKey('process_id', $record['extra']);
$this->assertInternalType('int', $record['extra']['process_id']);
$this->assertGreaterThan(0, $record['extra']['process_id']);
$this->assertEquals(getmypid(), $record['extra']['process_id']);
}
}

@ -1,27 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Processor;
use Monolog\TestCase;
class UidProcessorTest extends TestCase
{
/**
* @covers Monolog\Processor\UidProcessor::__invoke
*/
public function testProcessor()
{
$processor = new UidProcessor();
$record = $processor($this->getRecord());
$this->assertArrayHasKey('uid', $record['extra']);
}
}

@ -1,68 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Processor;
use Monolog\TestCase;
class WebProcessorTest extends TestCase
{
public function testProcessor()
{
$server = array(
'REQUEST_URI' => 'A',
'REMOTE_ADDR' => 'B',
'REQUEST_METHOD' => 'C',
'HTTP_REFERER' => 'D',
'SERVER_NAME' => 'F',
);
$processor = new WebProcessor($server);
$record = $processor($this->getRecord());
$this->assertEquals($server['REQUEST_URI'], $record['extra']['url']);
$this->assertEquals($server['REMOTE_ADDR'], $record['extra']['ip']);
$this->assertEquals($server['REQUEST_METHOD'], $record['extra']['http_method']);
$this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']);
$this->assertEquals($server['SERVER_NAME'], $record['extra']['server']);
}
public function testProcessorDoNothingIfNoRequestUri()
{
$server = array(
'REMOTE_ADDR' => 'B',
'REQUEST_METHOD' => 'C',
);
$processor = new WebProcessor($server);
$record = $processor($this->getRecord());
$this->assertEmpty($record['extra']);
}
public function testProcessorReturnNullIfNoHttpReferer()
{
$server = array(
'REQUEST_URI' => 'A',
'REMOTE_ADDR' => 'B',
'REQUEST_METHOD' => 'C',
'SERVER_NAME' => 'F',
);
$processor = new WebProcessor($server);
$record = $processor($this->getRecord());
$this->assertNull($record['extra']['referrer']);
}
/**
* @expectedException UnexpectedValueException
*/
public function testInvalidData()
{
new WebProcessor(new \stdClass);
}
}

@ -1,47 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog;
use Monolog\Handler\TestHandler;
use Monolog\Formatter\LineFormatter;
use Monolog\Processor\PsrLogMessageProcessor;
use Psr\Log\Test\LoggerInterfaceTest;
class PsrLogCompatTest extends LoggerInterfaceTest
{
private $handler;
public function getLogger()
{
$logger = new Logger('foo');
$logger->pushHandler($handler = new TestHandler);
$logger->pushProcessor(new PsrLogMessageProcessor);
$handler->setFormatter(new LineFormatter('%level_name% %message%'));
$this->handler = $handler;
return $logger;
}
public function getLogs()
{
$convert = function ($record) {
$lower = function ($match) {
return strtolower($match[0]);
};
return preg_replace_callback('{^[A-Z]+}', $lower, $record['formatted']);
};
return array_map($convert, $this->handler->getRecords());
}
}

@ -1,58 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog;
class TestCase extends \PHPUnit_Framework_TestCase
{
/**
* @return array Record
*/
protected function getRecord($level = Logger::WARNING, $message = 'test', $context = array())
{
return array(
'message' => $message,
'context' => $context,
'level' => $level,
'level_name' => Logger::getLevelName($level),
'channel' => 'test',
'datetime' => \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true))),
'extra' => array(),
);
}
/**
* @return array
*/
protected function getMultipleRecords()
{
return array(
$this->getRecord(Logger::DEBUG, 'debug message 1'),
$this->getRecord(Logger::DEBUG, 'debug message 2'),
$this->getRecord(Logger::INFO, 'information'),
$this->getRecord(Logger::WARNING, 'warning'),
$this->getRecord(Logger::ERROR, 'error')
);
}
/**
* @return Monolog\Formatter\FormatterInterface
*/
protected function getIdentityFormatter()
{
$formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface');
$formatter->expects($this->any())
->method('format')
->will($this->returnCallback(function($record) { return $record['message']; }));
return $formatter;
}
}

@ -1,13 +0,0 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
$loader = require_once __DIR__ . "/../vendor/autoload.php";
$loader->add('Monolog\\', __DIR__);

@ -1,6 +1,11 @@
CHANGELOG
=========
2.4.0
-----
* added the ability to define an idle timeout
2.3.0
-----

@ -33,8 +33,13 @@ class PhpExecutableFinder
*/
public function find()
{
// HHVM support
if (defined('HHVM_VERSION') && false !== $hhvm = getenv('PHP_BINARY')) {
return $hhvm;
}
// PHP_BINARY return the current sapi executable
if (defined('PHP_BINARY') && PHP_BINARY && ('cli' === PHP_SAPI) && is_file(PHP_BINARY)) {
if (defined('PHP_BINARY') && PHP_BINARY && in_array(PHP_SAPI, array('cli', 'cli-server')) && is_file(PHP_BINARY)) {
return PHP_BINARY;
}

@ -13,6 +13,7 @@ namespace Symfony\Component\Process;
use Symfony\Component\Process\Exception\InvalidArgumentException;
use Symfony\Component\Process\Exception\LogicException;
use Symfony\Component\Process\Exception\ProcessTimedOutException;
use Symfony\Component\Process\Exception\RuntimeException;
/**
@ -45,7 +46,9 @@ class Process
private $env;
private $stdin;
private $starttime;
private $lastOutputTime;
private $timeout;
private $idleTimeout;
private $options;
private $exitcode;
private $fallbackExitcode;
@ -54,15 +57,15 @@ class Process
private $stderr;
private $enhanceWindowsCompatibility;
private $enhanceSigchildCompatibility;
private $pipes;
private $process;
private $status = self::STATUS_READY;
private $incrementalOutputOffset;
private $incrementalErrorOutputOffset;
private $tty;
private $fileHandles;
private $readBytes;
private $useFileHandles = false;
/** @var ProcessPipes */
private $processPipes;
private static $sigchild;
@ -120,10 +123,10 @@ class Process
* Constructor.
*
* @param string $commandline The command line to run
* @param string $cwd The working directory
* @param array $env The environment variables or null to inherit
* @param string $stdin The STDIN content
* @param integer $timeout The timeout in seconds
* @param string|null $cwd The working directory or null to use the working dir of the current PHP process
* @param array|null $env The environment variables or null to inherit
* @param string|null $stdin The STDIN content
* @param integer|float|null $timeout The timeout in seconds or null to disable
* @param array $options An array of options for proc_open
*
* @throws RuntimeException When proc_open is not installed
@ -139,8 +142,8 @@ class Process
$this->commandline = $commandline;
$this->cwd = $cwd;
// on windows, if the cwd changed via chdir(), proc_open defaults to the dir where php was started
// on gnu/linux, PHP builds with --enable-maintainer-zts are also affected
// on Windows, if the cwd changed via chdir(), proc_open defaults to the dir where PHP was started
// on Gnu/Linux, PHP builds with --enable-maintainer-zts are also affected
// @see : https://bugs.php.net/bug.php?id=51800
// @see : https://bugs.php.net/bug.php?id=50524
@ -154,6 +157,7 @@ class Process
}
$this->stdin = $stdin;
$this->setTimeout($timeout);
$this->useFileHandles = defined('PHP_WINDOWS_VERSION_BUILD');
$this->enhanceWindowsCompatibility = true;
$this->enhanceSigchildCompatibility = !defined('PHP_WINDOWS_VERSION_BUILD') && $this->isSigchildEnabled();
$this->options = array_replace(array('suppress_errors' => true, 'binary_pipes' => true), $options);
@ -180,7 +184,7 @@ class Process
* The STDOUT and STDERR are also available after the process is finished
* via the getOutput() and getErrorOutput() methods.
*
* @param callback|null $callback A PHP callback to run whenever there is some
* @param callable|null $callback A PHP callback to run whenever there is some
* output available on STDOUT or STDERR
*
* @return integer The exit status code
@ -211,9 +215,11 @@ class Process
* with true as a second parameter then the callback will get all data occurred
* in (and since) the start call.
*
* @param callback|null $callback A PHP callback to run whenever there is some
* @param callable|null $callback A PHP callback to run whenever there is some
* output available on STDOUT or STDERR
*
* @return Process The process itself
*
* @throws RuntimeException When process can't be launch or is stopped
* @throws RuntimeException When process is already running
*/
@ -224,7 +230,7 @@ class Process
}
$this->resetProcessData();
$this->starttime = microtime(true);
$this->starttime = $this->lastOutputTime = microtime(true);
$this->callback = $this->buildCallback($callback);
$descriptors = $this->getDescriptors();
@ -237,18 +243,15 @@ class Process
}
}
$this->process = proc_open($commandline, $descriptors, $this->pipes, $this->cwd, $this->env, $this->options);
$this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $this->env, $this->options);
if (!is_resource($this->process)) {
throw new RuntimeException('Unable to launch a new process.');
}
$this->status = self::STATUS_STARTED;
foreach ($this->pipes as $pipe) {
stream_set_blocking($pipe, false);
}
$this->writePipes();
$this->processPipes->unblock();
$this->processPipes->write(false, $this->stdin);
$this->updateStatus(false);
$this->checkTimeout();
}
@ -258,13 +261,13 @@ class Process
*
* Be warned that the process is cloned before being started.
*
* @param callable $callback A PHP callback to run whenever there is some
* @param callable|null $callback A PHP callback to run whenever there is some
* output available on STDOUT or STDERR
*
* @return Process The new process
*
* @throws \RuntimeException When process can't be launch or is stopped
* @throws \RuntimeException When process is already running
* @throws RuntimeException When process can't be launch or is stopped
* @throws RuntimeException When process is already running
*
* @see start()
*/
@ -287,12 +290,12 @@ class Process
* from the output in real-time while writing the standard input to the process.
* It allows to have feedback from the independent process during execution.
*
* @param callback|null $callback A valid PHP callback
* @param callable|null $callback A valid PHP callback
*
* @return integer The exitcode of the process
*
* @throws \RuntimeException When process timed out
* @throws \RuntimeException When process stopped after receiving signal
* @throws RuntimeException When process timed out
* @throws RuntimeException When process stopped after receiving signal
*/
public function wait($callback = null)
{
@ -300,22 +303,15 @@ class Process
if (null !== $callback) {
$this->callback = $this->buildCallback($callback);
}
while ($this->pipes || (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles)) {
$this->checkTimeout();
$this->readPipes(true);
}
$this->updateStatus(false);
if ($this->processInformation['signaled']) {
if ($this->isSigchildEnabled()) {
throw new RuntimeException('The process has been signaled.');
}
throw new RuntimeException(sprintf('The process has been signaled with signal "%s".', $this->processInformation['termsig']));
}
do {
$this->checkTimeout();
$running = defined('PHP_WINDOWS_VERSION_BUILD') ? $this->isRunning() : $this->processPipes->hasOpenHandles();
$close = !defined('PHP_WINDOWS_VERSION_BUILD') || !$running;;
$this->readPipes(true, $close);
} while ($running);
$time = 0;
while ($this->isRunning() && $time < 1000000) {
$time += 1000;
while ($this->isRunning()) {
usleep(1000);
}
@ -349,9 +345,9 @@ class Process
}
/**
* Sends a posix signal to the process.
* Sends a POSIX signal to the process.
*
* @param integer $signal A valid posix signal (see http://www.php.net/manual/en/pcntl.constants.php)
* @param integer $signal A valid POSIX signal (see http://www.php.net/manual/en/pcntl.constants.php)
* @return Process
*
* @throws LogicException In case the process is not running
@ -384,7 +380,7 @@ class Process
*/
public function getOutput()
{
$this->readPipes(false);
$this->readPipes(false, defined('PHP_WINDOWS_VERSION_BUILD') ? !$this->processInformation['running'] : true);
return $this->stdout;
}
@ -407,6 +403,19 @@ class Process
return $latest;
}
/**
* Clears the process output.
*
* @return Process
*/
public function clearOutput()
{
$this->stdout = '';
$this->incrementalOutputOffset = 0;
return $this;
}
/**
* Returns the current error output of the process (STDERR).
*
@ -416,7 +425,7 @@ class Process
*/
public function getErrorOutput()
{
$this->readPipes(false);
$this->readPipes(false, defined('PHP_WINDOWS_VERSION_BUILD') ? !$this->processInformation['running'] : true);
return $this->stderr;
}
@ -440,6 +449,19 @@ class Process
return $latest;
}
/**
* Clears the process output.
*
* @return Process
*/
public function clearErrorOutput()
{
$this->stderr = '';
$this->incrementalErrorOutputOffset = 0;
return $this;
}
/**
* Returns the exit code returned by the process.
*
@ -622,7 +644,7 @@ class Process
* Stops the process.
*
* @param integer|float $timeout The timeout in seconds
* @param integer $signal A posix signal to send in case the process has not stop at timeout, default is SIGKILL
* @param integer $signal A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL
*
* @return integer The exit-code of the process
*
@ -642,9 +664,13 @@ class Process
$this->signal($signal ?: SIGKILL);
}
}
}
$this->updateStatus(false);
if ($this->processInformation['running']) {
$this->close();
}
$this->status = self::STATUS_TERMINATED;
return $this->exitcode;
@ -657,6 +683,7 @@ class Process
*/
public function addOutput($line)
{
$this->lastOutputTime = microtime(true);
$this->stdout .= $line;
}
@ -667,6 +694,7 @@ class Process
*/
public function addErrorOutput($line)
{
$this->lastOutputTime = microtime(true);
$this->stderr .= $line;
}
@ -697,19 +725,29 @@ class Process
/**
* Gets the process timeout.
*
* @return integer|null The timeout in seconds or null if it's disabled
* @return float|null The timeout in seconds or null if it's disabled
*/
public function getTimeout()
{
return $this->timeout;
}
/**
* Gets the process idle timeout.
*
* @return float|null
*/
public function getIdleTimeout()
{
return $this->idleTimeout;
}
/**
* Sets the process timeout.
*
* To disable the timeout, set this value to null.
*
* @param float|null $timeout The timeout in seconds
* @param integer|float|null $timeout The timeout in seconds
*
* @return self The current Process instance
*
@ -717,19 +755,23 @@ class Process
*/
public function setTimeout($timeout)
{
if (null === $timeout) {
$this->timeout = null;
$this->timeout = $this->validateTimeout($timeout);
return $this;
}
$timeout = (float) $timeout;
if ($timeout < 0) {
throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
}
$this->timeout = $timeout;
/**
* Sets the process idle timeout.
*
* @param integer|float|null $timeout
*
* @return self The current Process instance.
*
* @throws InvalidArgumentException if the timeout is negative
*/
public function setIdleTimeout($timeout)
{
$this->idleTimeout = $this->validateTimeout($timeout);
return $this;
}
@ -761,11 +803,10 @@ class Process
/**
* Gets the working directory.
*
* @return string The current working directory
* @return string|null The current working directory or null on failure
*/
public function getWorkingDirectory()
{
// This is for BC only
if (null === $this->cwd) {
// getcwd() will return false if any one of the parent directories does not have
// the readable or search mode set, even if the current directory does
@ -828,7 +869,7 @@ class Process
/**
* Gets the contents of STDIN.
*
* @return string The current contents
* @return string|null The current contents
*/
public function getStdin()
{
@ -838,7 +879,7 @@ class Process
/**
* Sets the contents of STDIN.
*
* @param string $stdin The new contents
* @param string|null $stdin The new contents
*
* @return self The current Process instance
*/
@ -933,14 +974,20 @@ class Process
* In case you run a background process (with the start method), you should
* trigger this method regularly to ensure the process timeout
*
* @throws RuntimeException In case the timeout was reached
* @throws ProcessTimedOutException In case the timeout was reached
*/
public function checkTimeout()
{
if (0 < $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
$this->stop(0);
throw new RuntimeException('The process timed-out.');
throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL);
}
if (0 < $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {
$this->stop(0);
throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE);
}
}
@ -951,38 +998,10 @@ class Process
*/
private function getDescriptors()
{
//Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big.
//Workaround for this problem is to use temporary files instead of pipes on Windows platform.
//@see https://bugs.php.net/bug.php?id=51800
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->fileHandles = array(
self::STDOUT => tmpfile(),
);
if (false === $this->fileHandles[self::STDOUT]) {
throw new RuntimeException('A temporary file could not be opened to write the process output to, verify that your TEMP environment variable is writable');
}
$this->readBytes = array(
self::STDOUT => 0,
);
return array(array('pipe', 'r'), $this->fileHandles[self::STDOUT], array('pipe', 'w'));
}
if ($this->tty) {
$descriptors = array(
array('file', '/dev/tty', 'r'),
array('file', '/dev/tty', 'w'),
array('file', '/dev/tty', 'w'),
);
} else {
$descriptors = array(
array('pipe', 'r'), // stdin
array('pipe', 'w'), // stdout
array('pipe', 'w'), // stderr
);
}
$this->processPipes = new ProcessPipes($this->useFileHandles);
$descriptors = $this->processPipes->getDescriptors();
if ($this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
// last exit code is output on the fourth pipe and caught to work around --enable-sigchild
$descriptors = array_merge($descriptors, array(array('pipe', 'w')));
@ -998,9 +1017,9 @@ class Process
* The callbacks adds all occurred output to the specific buffer and calls
* the user callback (if present) with the received output.
*
* @param callback|null $callback The user defined PHP callback
* @param callable|null $callback The user defined PHP callback
*
* @return callback A PHP callable
* @return callable A PHP callable
*/
protected function buildCallback($callback)
{
@ -1033,10 +1052,11 @@ class Process
return;
}
$this->readPipes($blocking);
$this->processInformation = proc_get_status($this->process);
$this->captureExitCode();
$this->readPipes($blocking, defined('PHP_WINDOWS_VERSION_BUILD') ? !$this->processInformation['running'] : true);
if (!$this->processInformation['running']) {
$this->close();
$this->status = self::STATUS_TERMINATED;
@ -1061,166 +1081,49 @@ class Process
}
/**
* Handles the windows file handles fallbacks.
* Validates and returns the filtered timeout.
*
* @param Boolean $closeEmptyHandles if true, handles that are empty will be assumed closed
*/
private function processFileHandles($closeEmptyHandles = false)
{
$fh = $this->fileHandles;
foreach ($fh as $type => $fileHandle) {
fseek($fileHandle, $this->readBytes[$type]);
$data = fread($fileHandle, 8192);
if (strlen($data) > 0) {
$this->readBytes[$type] += strlen($data);
call_user_func($this->callback, $type == 1 ? self::OUT : self::ERR, $data);
}
if (false === $data || ($closeEmptyHandles && '' === $data && feof($fileHandle))) {
fclose($fileHandle);
unset($this->fileHandles[$type]);
}
}
}
/**
* Returns true if a system call has been interrupted.
* @param integer|float|null $timeout
*
* @return Boolean
* @return float|null
*/
private function hasSystemCallBeenInterrupted()
private function validateTimeout($timeout)
{
$lastError = error_get_last();
// stream_select returns false when the `select` system call is interrupted by an incoming signal
return isset($lastError['message']) && false !== stripos($lastError['message'], 'interrupted system call');
}
/**
* Reads pipes, executes callback.
*
* @param Boolean $blocking Whether to use blocking calls or not.
*/
private function readPipes($blocking)
{
if (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles) {
$this->processFileHandles(!$this->pipes);
}
if ($this->pipes) {
$r = $this->pipes;
$w = null;
$e = null;
// let's have a look if something changed in streams
if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? ceil(self::TIMEOUT_PRECISION * 1E6) : 0)) {
// if a system call has been interrupted, forget about it, let's try again
// otherwise, an error occured, let's reset pipes
if (!$this->hasSystemCallBeenInterrupted()) {
$this->pipes = array();
}
return;
}
$timeout = (float) $timeout;
// nothing has changed
if (0 === $n) {
return;
if (0.0 === $timeout) {
$timeout = null;
} elseif ($timeout < 0) {
throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
}
$this->processReadPipes($r);
}
return $timeout;
}
/**
* Writes data to pipes.
* Reads pipes, executes callback.
*
* @param Boolean $blocking Whether to use blocking calls or not.
*/
private function writePipes()
private function readPipes($blocking, $close)
{
if ($this->tty) {
$this->status = self::STATUS_TERMINATED;
return;
}
if (null === $this->stdin) {
fclose($this->pipes[0]);
unset($this->pipes[0]);
return;
}
$writePipes = array($this->pipes[0]);
unset($this->pipes[0]);
$stdinLen = strlen($this->stdin);
$stdinOffset = 0;
while ($writePipes) {
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->processFileHandles();
}
$r = $this->pipes;
$w = $writePipes;
$e = null;
if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? ceil(static::TIMEOUT_PRECISION * 1E6) : 0)) {
// if a system call has been interrupted, forget about it, let's try again
if ($this->hasSystemCallBeenInterrupted()) {
continue;
}
break;
}
// nothing has changed, let's wait until the process is ready
if (0 === $n) {
continue;
}
if ($w) {
$written = fwrite($writePipes[0], (binary) substr($this->stdin, $stdinOffset), 8192);
if (false !== $written) {
$stdinOffset += $written;
}
if ($stdinOffset >= $stdinLen) {
fclose($writePipes[0]);
$writePipes = null;
}
}
$this->processReadPipes($r);
}
if ($close) {
$result = $this->processPipes->readAndCloseHandles($blocking);
} else {
$result = $this->processPipes->read($blocking);
}
/**
* Processes read pipes, executes callback on it.
*
* @param array $pipes
*/
private function processReadPipes(array $pipes)
{
foreach ($pipes as $pipe) {
$type = array_search($pipe, $this->pipes);
$data = fread($pipe, 8192);
if (strlen($data) > 0) {
// last exit code is output and caught to work around --enable-sigchild
foreach ($result as $type => $data) {
if (3 == $type) {
$this->fallbackExitcode = (int) $data;
} else {
call_user_func($this->callback, $type == 1 ? self::OUT : self::ERR, $data);
}
}
if (false === $data || feof($pipe)) {
fclose($pipe);
unset($this->pipes[$type]);
call_user_func($this->callback, $type === self::STDOUT ? self::OUT : self::ERR, $data);
}
}
}
/**
* Captures the exitcode if mentioned in the process informations.
* Captures the exitcode if mentioned in the process information.
*/
private function captureExitCode()
{
@ -1229,7 +1132,6 @@ class Process
}
}
/**
* Closes process resource, closes file handles, sets the exitcode.
*
@ -1237,13 +1139,9 @@ class Process
*/
private function close()
{
foreach ($this->pipes as $pipe) {
fclose($pipe);
}
$this->pipes = null;
$exitcode = -1;
$this->processPipes->close();
if (is_resource($this->process)) {
$exitcode = proc_close($this->process);
}
@ -1254,17 +1152,10 @@ class Process
if (-1 == $this->exitcode && null !== $this->fallbackExitcode) {
$this->exitcode = $this->fallbackExitcode;
} elseif (-1 === $this->exitcode && $this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
// if process has been signaled, no exitcode but a valid termsig, apply unix convention
// if process has been signaled, no exitcode but a valid termsig, apply Unix convention
$this->exitcode = 128 + $this->processInformation['termsig'];
}
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
foreach ($this->fileHandles as $fileHandle) {
fclose($fileHandle);
}
$this->fileHandles = array();
}
return $this->exitcode;
}
@ -1280,11 +1171,8 @@ class Process
$this->processInformation = null;
$this->stdout = null;
$this->stderr = null;
$this->pipes = null;
$this->process = null;
$this->status = self::STATUS_READY;
$this->fileHandles = null;
$this->readBytes = null;
$this->incrementalOutputOffset = 0;
$this->incrementalErrorOutputOffset = 0;
}

@ -23,21 +23,16 @@ class ProcessBuilder
{
private $arguments;
private $cwd;
private $env;
private $env = array();
private $stdin;
private $timeout;
private $options;
private $inheritEnv;
private $prefix;
private $timeout = 60;
private $options = array();
private $inheritEnv = true;
private $prefix = array();
public function __construct(array $arguments = array())
{
$this->arguments = $arguments;
$this->timeout = 60;
$this->options = array();
$this->env = array();
$this->inheritEnv = true;
}
public static function create(array $arguments = array())
@ -62,15 +57,15 @@ class ProcessBuilder
/**
* Adds an unescaped prefix to the command string.
*
* The prefix is preserved when reseting arguments.
* The prefix is preserved when resetting arguments.
*
* @param string $prefix A command prefix
* @param string|array $prefix A command prefix or an array of command prefixes
*
* @return ProcessBuilder
*/
public function setPrefix($prefix)
{
$this->prefix = $prefix;
$this->prefix = is_array($prefix) ? $prefix : array($prefix);
return $this;
}
@ -108,6 +103,13 @@ class ProcessBuilder
return $this;
}
public function addEnvironmentVariables(array $variables)
{
$this->env = array_replace($this->env, $variables);
return $this;
}
public function setInput($stdin)
{
$this->stdin = $stdin;
@ -154,17 +156,18 @@ class ProcessBuilder
public function getProcess()
{
if (!$this->prefix && !count($this->arguments)) {
if (0 === count($this->prefix) && 0 === count($this->arguments)) {
throw new LogicException('You must add() command arguments before calling getProcess().');
}
$options = $this->options;
$arguments = $this->prefix ? array_merge(array($this->prefix), $this->arguments) : $this->arguments;
$arguments = array_merge($this->prefix, $this->arguments);
$script = implode(' ', array_map(array(__NAMESPACE__.'\\ProcessUtils', 'escapeArgument'), $arguments));
if ($this->inheritEnv) {
$env = $this->env ? $this->env + $_ENV : null;
// include $_ENV for BC purposes
$env = array_replace($_ENV, $_SERVER, $this->env);
} else {
$env = $this->env;
}

@ -37,7 +37,7 @@ class ProcessUtils
public static function escapeArgument($argument)
{
//Fix for PHP bug #43784 escapeshellarg removes % from given string
//Fix for PHP bug #49446 escapeshellarg dosn`t work on windows
//Fix for PHP bug #49446 escapeshellarg doesn't work on Windows
//@see https://bugs.php.net/bug.php?id=43784
//@see https://bugs.php.net/bug.php?id=49446
if (defined('PHP_WINDOWS_VERSION_BUILD')) {

@ -43,5 +43,5 @@ Resources
You can run the unit tests with the following command:
$ cd path/to/Symfony/Component/XXX/
$ composer.phar install --dev
$ composer.phar install
$ phpunit

@ -11,6 +11,7 @@
namespace Symfony\Component\Process\Tests;
use Symfony\Component\Process\Exception\ProcessTimedOutException;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\RuntimeException;
@ -19,6 +20,16 @@ use Symfony\Component\Process\Exception\RuntimeException;
*/
abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
{
public function testThatProcessDoesNotThrowWarningDuringRun()
{
@trigger_error('Test Error', E_USER_NOTICE);
$process = $this->getProcess("php -r 'sleep(3)'");
$process->run();
$actualError = error_get_last();
$this->assertEquals('Test Error', $actualError['message']);
$this->assertEquals(E_USER_NOTICE, $actualError['type']);
}
/**
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
*/
@ -36,12 +47,17 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
$p->setTimeout(-1);
}
public function testNullTimeout()
public function testFloatAndNullTimeout()
{
$p = $this->getProcess('');
$p->setTimeout(10);
$this->assertSame(10.0, $p->getTimeout());
$p->setTimeout(null);
$this->assertNull($p->getTimeout());
$p->setTimeout(0.0);
$this->assertNull($p->getTimeout());
}
@ -69,17 +85,16 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
{
$data = '';
$process = $this->getProcess('echo "foo";sleep 1;echo "foo"');
$process = $this->getProcess('echo foo && php -r "sleep(1);" && echo foo');
$process->start(function ($type, $buffer) use (&$data) {
$data .= $buffer;
});
$start = microtime(true);
while ($process->isRunning()) {
usleep(10000);
}
$this->assertEquals("foo\nfoo\n", $data);
$this->assertEquals(2, preg_match_all('/foo/', $data, $matches));
}
/**
@ -102,10 +117,6 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
*/
public function testProcessPipes($code, $size)
{
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->markTestSkipped('Test hangs on Windows & PHP due to https://bugs.php.net/bug.php?id=60120 and https://bugs.php.net/bug.php?id=51800');
}
$expected = str_repeat(str_repeat('*', 1024), $size) . '!';
$expectedLength = (1024 * $size) + 1;
@ -119,6 +130,12 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
public function chainedCommandsOutputProvider()
{
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
return array(
array("2 \r\n2\r\n", '&&', '2')
);
}
return array(
array("1\n1\n", ';', '1'),
array("2\n2\n", '&&', '2'),
@ -131,10 +148,6 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
*/
public function testChainedCommandsOutput($expected, $operator, $input)
{
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->markTestSkipped('Does it work on windows ?');
}
$process = $this->getProcess(sprintf('echo %s %s echo %s', $input, $operator, $input));
$process->run();
$this->assertEquals($expected, $process->getOutput());
@ -171,9 +184,18 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
}
}
public function testFlushErrorOutput()
{
$p = new Process(sprintf('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; }')));
$p->run();
$p->clearErrorOutput();
$this->assertEmpty($p->getErrorOutput());
}
public function testGetOutput()
{
$p = new Process(sprintf('php -r %s', escapeshellarg('$n=0;while ($n<3) {echo \' foo \';$n++;}')));
$p = new Process(sprintf('php -r %s', escapeshellarg('$n=0;while ($n<3) {echo \' foo \';$n++; usleep(500); }')));
$p->run();
$this->assertEquals(3, preg_match_all('/foo/', $p->getOutput(), $matches));
@ -190,6 +212,15 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
}
}
public function testFlushOutput()
{
$p = new Process(sprintf('php -r %s', escapeshellarg('$n=0;while ($n<3) {echo \' foo \';$n++;}')));
$p->run();
$p->clearOutput();
$this->assertEmpty($p->getOutput());
}
public function testExitCodeCommandFailed()
{
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
@ -308,7 +339,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
public function testIsSuccessfulOnlyAfterTerminated()
{
$process = $this->getProcess('sleep 1');
$process = $this->getProcess('php -r "sleep(1);"');
$process->start();
while ($process->isRunning()) {
$this->assertFalse($process->isSuccessful());
@ -428,7 +459,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
public function testPhpDeadlock()
{
$this->markTestSkipped('Can course php to hang');
$this->markTestSkipped('Can course PHP to hang');
// Sleep doesn't work as it will allow the process to handle signals and close
// file handles from the other end.
@ -441,7 +472,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
public function testRunProcessWithTimeout()
{
$timeout = 0.5;
$process = $this->getProcess('sleep 3');
$process = $this->getProcess('php -r "sleep(3);"');
$process->setTimeout($timeout);
$start = microtime(true);
try {
@ -459,7 +490,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
{
$timeout = 0.5;
$precision = 100000;
$process = $this->getProcess('sleep 3');
$process = $this->getProcess('php -r "sleep(3);"');
$process->setTimeout($timeout);
$start = microtime(true);
@ -480,6 +511,60 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($process->isSuccessful());
}
/**
* @group idle-timeout
*/
public function testIdleTimeout()
{
$process = $this->getProcess('sleep 3');
$process->setTimeout(10);
$process->setIdleTimeout(1);
try {
$process->run();
$this->fail('A timeout exception was expected.');
} catch (ProcessTimedOutException $ex) {
$this->assertTrue($ex->isIdleTimeout());
$this->assertFalse($ex->isGeneralTimeout());
$this->assertEquals(1.0, $ex->getExceededTimeout());
}
}
/**
* @group idle-timeout
*/
public function testIdleTimeoutNotExceededWhenOutputIsSent()
{
$process = $this->getProcess('echo "foo" && sleep 1 && echo "foo" && sleep 1 && echo "foo" && sleep 1 && echo "foo" && sleep 5');
$process->setTimeout(5);
$process->setIdleTimeout(3);
try {
$process->run();
$this->fail('A timeout exception was expected.');
} catch (ProcessTimedOutException $ex) {
$this->assertTrue($ex->isGeneralTimeout());
$this->assertFalse($ex->isIdleTimeout());
$this->assertEquals(5.0, $ex->getExceededTimeout());
}
}
public function testStartAfterATimeout()
{
$process = $this->getProcess('php -r "while (true) {echo \'\'; usleep(1000); }"');
$process->setTimeout(0.1);
try {
$process->run();
$this->fail('An exception should have been raised.');
} catch (\Exception $e) {
}
$process->start();
usleep(10000);
$process->stop();
}
public function testGetPid()
{
$process = $this->getProcess('php -r "sleep(1);"');
@ -536,7 +621,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
}
/**
* @expectedException Symfony\Component\Process\Exception\LogicException
* @expectedException \Symfony\Component\Process\Exception\LogicException
*/
public function testSignalProcessNotRunning()
{
@ -548,7 +633,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
private function verifyPosixIsEnabled()
{
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->markTestSkipped('POSIX signals do not work on windows');
$this->markTestSkipped('POSIX signals do not work on Windows');
}
if (!defined('SIGUSR1')) {
$this->markTestSkipped('The pcntl extension is not enabled');
@ -556,12 +641,12 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
}
/**
* @expectedException Symfony\Component\Process\Exception\RuntimeException
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
*/
public function testSignalWithWrongIntSignal()
{
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->markTestSkipped('POSIX signals do not work on windows');
$this->markTestSkipped('POSIX signals do not work on Windows');
}
$process = $this->getProcess('php -r "sleep(3);"');
@ -570,12 +655,12 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
}
/**
* @expectedException Symfony\Component\Process\Exception\RuntimeException
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
*/
public function testSignalWithWrongNonIntSignal()
{
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->markTestSkipped('POSIX signals do not work on windows');
$this->markTestSkipped('POSIX signals do not work on Windows');
}
$process = $this->getProcess('php -r "sleep(3);"');
@ -597,11 +682,18 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
{
$variations = array(
'fwrite(STDOUT, $in = file_get_contents(\'php://stdin\')); fwrite(STDERR, $in);',
'include \''.__DIR__.'/ProcessTestHelper.php\';',
'include \''.__DIR__.'/PipeStdinInStdoutStdErrStreamSelect.php\';',
);
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
// Avoid XL buffers on Windows because of https://bugs.php.net/bug.php?id=65650
$sizes = array(1, 2, 4, 8);
} else {
$sizes = array(1, 16, 64, 1024, 4096);
}
$codes = array();
foreach (array(1, 16, 64, 1024, 4096) as $size) {
foreach ($sizes as $size) {
foreach ($variations as $code) {
$codes[] = array($code, $size);
}

@ -33,11 +33,11 @@ class PhpExecutableFinderTest extends \PHPUnit_Framework_TestCase
//not executable PHP_PATH
putenv('PHP_PATH=/not/executable/php');
$this->assertFalse($f->find(), '::find() returns false for not executable php');
$this->assertFalse($f->find(), '::find() returns false for not executable PHP');
//executable PHP_PATH
putenv('PHP_PATH='.$current);
$this->assertEquals($f->find(), $current, '::find() returns the executable php');
$this->assertEquals($f->find(), $current, '::find() returns the executable PHP');
}
/**
@ -55,10 +55,10 @@ class PhpExecutableFinderTest extends \PHPUnit_Framework_TestCase
$current = $f->find();
//TODO maybe php executable is custom or even windows
//TODO maybe php executable is custom or even Windows
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->assertTrue(is_executable($current));
$this->assertTrue((bool) preg_match('/'.addSlashes(DIRECTORY_SEPARATOR).'php\.(exe|bat|cmd|com)$/i', $current), '::find() returns the executable php with suffixes');
$this->assertTrue((bool) preg_match('/'.addSlashes(DIRECTORY_SEPARATOR).'php\.(exe|bat|cmd|com)$/i', $current), '::find() returns the executable PHP with suffixes');
}
}
}

@ -17,75 +17,51 @@ class ProcessBuilderTest extends \PHPUnit_Framework_TestCase
{
public function testInheritEnvironmentVars()
{
$snapshot = $_ENV;
$_ENV = $expected = array('foo' => 'bar');
$_ENV['MY_VAR_1'] = 'foo';
$pb = new ProcessBuilder();
$pb->add('foo')->inheritEnvironmentVariables();
$proc = $pb->getProcess();
$this->assertNull($proc->getEnv(), '->inheritEnvironmentVariables() copies $_ENV');
$_ENV = $snapshot;
}
public function testProcessShouldInheritAndOverrideEnvironmentVars()
{
$snapshot = $_ENV;
$_ENV = array('foo' => 'bar', 'bar' => 'baz');
$expected = array('foo' => 'foo', 'bar' => 'baz');
$pb = new ProcessBuilder();
$pb->add('foo')->inheritEnvironmentVariables()
->setEnv('foo', 'foo');
$proc = $pb->getProcess();
$this->assertEquals($expected, $proc->getEnv(), '->inheritEnvironmentVariables() copies $_ENV');
$_ENV = $snapshot;
}
public function testProcessBuilderShouldNotPassEnvArrays()
{
$snapshot = $_ENV;
$_ENV = array('a' => array('b', 'c'), 'd' => 'e', 'f' => 'g');
$expected = array('d' => 'e', 'f' => 'g');
$pb = new ProcessBuilder();
$pb->add('a')->inheritEnvironmentVariables()
->setEnv('d', 'e');
$proc = $pb->getProcess();
$proc = ProcessBuilder::create()
->add('foo')
->getProcess();
$this->assertEquals($expected, $proc->getEnv(), '->inheritEnvironmentVariables() removes array values from $_ENV');
unset($_ENV['MY_VAR_1']);
$_ENV = $snapshot;
$env = $proc->getEnv();
$this->assertArrayHasKey('MY_VAR_1', $env);
$this->assertEquals('foo', $env['MY_VAR_1']);
}
public function testInheritEnvironmentVarsByDefault()
public function testAddEnvironmentVariables()
{
$pb = new ProcessBuilder();
$proc = $pb->add('foo')->getProcess();
$env = array(
'foo' => 'bar',
'foo2' => 'bar2',
);
$proc = $pb
->add('command')
->setEnv('foo', 'bar2')
->addEnvironmentVariables($env)
->inheritEnvironmentVariables(false)
->getProcess()
;
$this->assertNull($proc->getEnv());
$this->assertSame($env, $proc->getEnv());
}
public function testNotReplaceExplicitlySetVars()
public function testProcessShouldInheritAndOverrideEnvironmentVars()
{
$snapshot = $_ENV;
$_ENV = array('foo' => 'bar');
$expected = array('foo' => 'baz');
$_ENV['MY_VAR_1'] = 'foo';
$pb = new ProcessBuilder();
$pb
->setEnv('foo', 'baz')
->inheritEnvironmentVariables()
$proc = ProcessBuilder::create()
->setEnv('MY_VAR_1', 'bar')
->add('foo')
;
$proc = $pb->getProcess();
->getProcess();
$this->assertEquals($expected, $proc->getEnv(), '->inheritEnvironmentVariables() copies $_ENV');
unset($_ENV['MY_VAR_1']);
$_ENV = $snapshot;
$env = $proc->getEnv();
$this->assertArrayHasKey('MY_VAR_1', $env);
$this->assertEquals('bar', $env['MY_VAR_1']);
}
/**
@ -140,6 +116,26 @@ class ProcessBuilderTest extends \PHPUnit_Framework_TestCase
}
}
public function testArrayPrefixesArePrependedToAllGeneratedProcess()
{
$pb = new ProcessBuilder();
$pb->setPrefix(array('/usr/bin/php', 'composer.phar'));
$proc = $pb->setArguments(array('-v'))->getProcess();
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->assertEquals('"/usr/bin/php" "composer.phar" "-v"', $proc->getCommandLine());
} else {
$this->assertEquals("'/usr/bin/php' 'composer.phar' '-v'", $proc->getCommandLine());
}
$proc = $pb->setArguments(array('-i'))->getProcess();
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->assertEquals('"/usr/bin/php" "composer.phar" "-i"', $proc->getCommandLine());
} else {
$this->assertEquals("'/usr/bin/php' 'composer.phar' '-i'", $proc->getCommandLine());
}
}
public function testShouldEscapeArguments()
{
$pb = new ProcessBuilder(array('%path%', 'foo " bar'));

@ -1,63 +0,0 @@
<?php
define('ERR_SELECT_FAILED', 1);
define('ERR_TIMEOUT', 2);
define('ERR_READ_FAILED', 3);
define('ERR_WRITE_FAILED', 4);
$read = array(STDIN);
$write = array(STDOUT, STDERR);
stream_set_blocking(STDIN, false);
stream_set_blocking(STDOUT, false);
stream_set_blocking(STDERR, false);
$out = $err = '';
while ($read || $write) {
$r = $read;
$w = $write;
$e = null;
$n = stream_select($r, $w, $e, 5);
if (false === $n) {
die(ERR_SELECT_FAILED);
} elseif ($n < 1) {
die(ERR_TIMEOUT);
}
if (in_array(STDOUT, $w) && strlen($out) > 0) {
$written = fwrite(STDOUT, (binary) $out, 1024);
if (false === $written) {
die(ERR_WRITE_FAILED);
}
$out = (binary) substr($out, $written);
}
if (null === $read && strlen($out) < 1) {
$write = array_diff($write, array(STDOUT));
}
if (in_array(STDERR, $w) && strlen($err) > 0) {
$written = fwrite(STDERR, (binary) $err, 1024);
if (false === $written) {
die(ERR_WRITE_FAILED);
}
$err = (binary) substr($err, $written);
}
if (null === $read && strlen($err) < 1) {
$write = array_diff($write, array(STDERR));
}
if ($r) {
$str = fread(STDIN, 1024);
if (false !== $str) {
$out .= $str;
$err .= $str;
}
if (false === $str || feof(STDIN)) {
$read = null;
if (!feof(STDIN)) {
die(ERR_READ_FAILED);
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save