rmzamora/zenddiagnostics

一组用于在PHP应用程序中执行诊断测试的组件

v1.0.9 2016-04-01 10:39 UTC

README

一个简单的组件,用于在现实世界的PHP应用程序中执行诊断测试。

ZendDiagnostics

它目前包含以下诊断检查:

  • ApcFragmentation - 检查APC内存碎片是否低于给定阈值,
  • ApcMemory - 检查可用的APC内存,
  • Callback - 调用一个用户定义的诊断函数,
  • ClassExists - 确保类在当前环境中存在,
  • CouchDBCheck - 检查是否可以建立连接,
  • CpuPerformance - 检查服务器CPU性能是否高于基线,
  • DirReadable - 确保给定路径可读,
  • DirWritable - 确保给定路径可写,
  • DiskFree - 检查给定路径是否有足够的空闲空间,
  • DiskUsage - 检查磁盘使用率是否低于警告/关键百分比阈值,
  • DoctrineMigration - 确保所有迁移都已应用。
  • ExtensionLoaded - 确保已加载扩展,
  • GuzzleHttpService - 使用Guzzle检查给定的HTTP主机是否响应,
  • HttpService - 检查给定的HTTP主机是否响应,
  • Memcache - 检查是否已加载memcache扩展且给定服务器可访问,
  • OpCacheMemory - 检查OpCache内存使用率是否低于警告/关键阈值,
  • PDOCheck - 检查是否可以建立连接,
  • PhpVersion - 确保PHP版本符合约束条件,
  • PhpFlag - 确保给定的PHP标志(功能)已打开或关闭。
  • ProcessRunning - 检查是否有具有给定名称或ID的进程正在运行,
  • RabbitMQ - 验证RabbitMQ服务正在运行,
  • Redis - 验证Redis服务正在运行,
  • SecurityAdvisory - 将安装的composer依赖项与SensioLabs SA数据库进行安全警告检查,
  • StreamWrapperExists - 确保给定流包装器可用。

文件验证检查

  • IniFile - 检查给定的INI文件是否存在且有效,
  • JsonFile - 检查给定的JSON文件是否存在且有效,
  • XmlFile - 检查给定的XML文件是否存在且有效,
  • YamlFile - 检查给定的YAML文件是否存在且有效

使用Zend Framework 2进行诊断

  1. 安装ZFTool模块
  2. 您的应用config.php配置文件中启用诊断测试。
  3. 在控制台输入php public/index.php diag以运行诊断。

使用Symfony 2进行诊断

  1. 安装LiipMonitorBundle
  2. 您的应用配置文件中启用诊断测试。
  3. 在控制台输入./app/console monitor:health以运行诊断。

使用PSR-7中间件进行诊断

安装rstgroup/diagnostics-middleware

在纯PHP中使用诊断

  1. 将ZendDiagnostics组件添加到您的应用中
  2. 如果您不使用Composer,请使用include "autoload_register.php";
  3. 创建ZendDiagnostics\Runner的一个实例
  4. 使用Runner::addTest()添加测试
  5. 可选地使用Runner::addReporter()添加一个报告器以显示进度
  6. 运行诊断Runner::run()

例如

// run_diagnostics.php

use ZendDiagnostics\Check;
use ZendDiagnostics\Runner\Runner;
use ZendDiagnostics\Runner\Reporter\BasicConsole;
use ZendDiagnostics\Check\DiskFree;

include 'autoload_register.php';

// Create Runner instance
$runner = new Runner();

// Add checks
$runner->addCheck(new Check\DirWritable('/tmp'));
$runner->addCheck(new Check\DiskFree('/tmp', 100000000));

// Add console reporter
$runner->addReporter(new BasicConsole(80, true));

// Run all checks
$runner->run();

现在您可以在控制台(命令行)中运行该文件

> php run_diagnostics.php
Starting diagnostics:

..

OK (2 diagnostic tests)

使用结果集合

运行器将始终返回一个Result.Collection(即使没有附加报告器)。此集合包含所有测试的结果和失败计数器。

简单示例

$runner = new Runner();
$checkSpace = new Check\DiskFree('/tmp', 100000000);
$checkTemp  = new Check\DirWritable('/tmp');
$runner->addCheck($checkSpace);
$runner->addCheck($checkTemp);

// Run all checks
$results = $runner->run();

echo "Number of successful tests: " . $results->getSuccessCount() . "\n";
echo "Number of failed tests:     " . $results->getFailureCount() . "\n";

if ($results[$checkSpace] instanceof \ZendDiagnostics\Result\FailureInterface) {
    echo "Oooops! We're running out of space on temp.\n";
}

if ($results[$checkTemp] instanceof \ZendDiagnostics\Result\FailureInterface) {
    echo "It seems that /tmp is not writable - this is a serious problem!\n";
}

架构

单个诊断Check对应用或环境执行一项特定的测试。

它必须返回一个实现以下结果接口之一的Result

  • Success - 如果检查成功运行且没有问题。
  • Warning - 如果可能存在问题。
  • Failure - 如果测试失败且需要干预。

每个测试Result还可以返回

  • 结果消息通过getMessage()。它可以用来描述结果的范围。
  • 结果数据通过getData()。这可以用来提供有关特定结果原因的详细信息,这可能对调试问题很有用。

可以定义额外的结果接口,即表示严重程度(例如,关键、警报、通知)或适当的操作(例如,缺失、不完整)。然而,为了与其他应用程序和库兼容,建议扩展主集的Success、Warning、Failure接口。

编写自定义检查

检查类必须实现Check并提供以下方法

interface CheckInterface
{
    /**
     * @return ResultInterface
     */
    public function check();

    /**
     * Return a label describing this test instance.
     *
     * @return string
     */
    public function getLabel();
}

主要的check()方法负责执行实际检查,并应返回一个Result。建议使用内置的结果类以实现与Runner和其他检查的兼容性。

以下是一个示例简单类,该类将检查PHP默认时区是否设置为UTC。

namespace MyApp\Diagnostics\Check;

use ZendDiagnostics\Check\CheckInterface;
use ZendDiagnostics\Result\Success;
use ZendDiagnostics\Result\Failure;

class TimezoneSetToUTC implements CheckInterface
{
    public function check()
    {
        $tz = date_default_timezone_get();

        if ($tz == 'UTC') {
            return new Success('Default timezone is UTC');
        } else {
            return new Failure('Default timezone is not UTC! It is actually ' . $tz);
        }
    }

    public function getLabel()
    {
        return 'Check if PHP default timezone is set to UTC';
    }
}

编写自定义报告器

报告器是一个实现ReporterInterface的类。

interface ReporterInterface
{
    public function onStart(ArrayObject $checks, $runnerConfig);
    public function onBeforeRun(Check $check);
    public function onAfterRun(Check $check, Result $result);
    public function onStop(ResultsCollection $results);
    public function onFinish(ResultsCollection $results);
}

运行诊断时,运行器按照以下顺序调用上述方法

  • onStart - 在调用Runner::run()后立即调用
  • onBeforeRun - 在每个单独的检查之前调用
  • onAfterRun - 在每个单独的检查运行完成后调用
  • onFinish - 在运行器完成其工作后调用
  • onStop - 如果运行器被中断
    • 当报告器从onAfterRun方法返回false
    • 或者当运行器配置为setBreakOnFailure(true)并且其中一个检查失败时

一些报告器方法可以用来中断运行器的操作

  • onBeforeRun(Check $check) - 如果此方法返回false,则将省略该特定的检查。
  • onAfterRun(Check $check, Result($result)) - 如果此方法返回false,运行器将终止检查。

所有其他返回值都被忽略。

ZendDiagnostics附带了简单的控制台报告器 - 它可以作为编写您自己的报告器的良好示例。

内置诊断检查

ZendDiagnostics提供了一些“只需加水即可”的检查,您可以直接使用。

以下是一些目前可用的内置测试

ApcFragmentation

确保APC内存碎片水平低于给定的阈值

<?php
use ZendDiagnostics\Check\ApcFragmentation;

// Display a warning with fragmentation > 50% and failure when above 90%
$fragmentation = new ApcFragmentation(50, 90);

ApcMemory

检查APC内存使用百分比并确保它低于给定的阈值。

<?php
use ZendDiagnostics\Check\ApcMemory;

// Display a warning with memory usage is above 70% and a failure above 90%
$checkFreeMemory = new ApcMemory(70, 90);

Callback

运行一个函数(回调)并将返回值用作结果

<?php
use ZendDiagnostics\Check\Callback;
use ZendDiagnostics\Result\Success;
use ZendDiagnostics\Result\Failure;

$checkDbFile = new Callback(function(){
    $path = __DIR__ . '/data/db.sqlite';
    if(is_file($path) && is_readable($path) && filesize($path)) {
        return new Success('Db file is ok');
    } else {
        return new Failure('There is something wrong with the db file');
    }
});

注意:回调必须返回一个boolean(成功为true,失败为false)或有效的ResultInterface实例。所有其他对象都将导致异常,而标量(例如,字符串)将被解释为警告。

ClassExists

检查一个类(或一组类)是否存在。例如

<?php
use ZendDiagnostics\Check\ClassExists;

$checkLuaClass    = new ClassExists('Lua');
$checkRbacClasses = new ClassExists(array(
    'ZfcRbac\Module',
    'ZfcRbac\Controller\Plugin\IsGranted'
));

CpuPerformance

基准测试CPU性能,如果性能低于给定的比率,则返回失败。性能计算的基准是Amazon EC2 Micro实例的速度(2013年第一季度)。您可以指定测试的预期性能,其中1.0(一)的比率表示至少与EC2 Micro实例的速度相同。比率2表示“至少是EC2 Micro实例性能的两倍”,而比率0.5表示“至少是Micro实例性能的一半”。

以下检查将测试当前服务器是否至少有EC2 Micro实例一半的CPU性能

<?php
use ZendDiagnostics\Check\CpuPerformance;

$checkMinCPUSpeed = new CpuPerformance(0.5); // at least 50% of EC2 micro instance

DirReadable

检查给定的路径(或一组路径)是否指向目录并且是可读的。

<?php
use ZendDiagnostics\Check\DirReadable;

$checkPublic = new DirReadable('public/');
$checkAssets = new DirReadable(array(
    __DIR__ . '/assets/img',
    __DIR__ . '/assets/js'
));

DirWritable

检查给定的路径(或路径数组)是否指向一个目录,并且是否可以写入。

<?php
use ZendDiagnostics\Check\DirWritable;

$checkTemporary = new DirWritable('/tmp');
$checkAssets    = new DirWritable(array(
    __DIR__ . '/assets/customImages',
    __DIR__ . '/assets/customJs',
    __DIR__ . '/assets/uploads',
));

DiskFree

检查是否有足够的剩余磁盘空间。

第一个参数是最低磁盘空间,可以是整数(以字节为单位,例如 1024),或者是一个带有乘数的字符串(IEC、SI或Jedec,例如 "150MB")。第二个参数是要检查的路径 - 在 *NIX 系统中它是一个普通路径(例如 /home),在Windows系统中它是一个驱动器字母(例如 "C:")。

<?php
use ZendDiagnostics\Check\DiskFree;

$tempHasAtLeast100Megs  = new DiskFree('100MB', '/tmp');
$homeHasAtLeast1TB      = new DiskFree('1TiB',  '/home');
$dataHasAtLeast900Bytes = new DiskFree(900, __DIR__ . '/data/');

ExtensionLoaded

检查PHP扩展(或扩展数组)当前是否已加载。

<?php
use ZendDiagnostics\Check\ExtensionLoaded;

$checkMbstring    = new ExtensionLoaded('mbstring');
$checkCompression = new ExtensionLoaded(array(
    'rar',
    'bzip2',
    'zip'
));

HttpService

尝试连接到给定的HTTP主机或IP地址并尝试加载网页。该检查还支持检查响应代码和页面内容。

<?php
use ZendDiagnostics\Check\HttpService;

// Try to connect to google.com
$checkGoogle = new HttpService('www.google.com');

// Check port 8080 on localhost
$checkLocal = new HttpService('127.0.0.1', 8080);

// Check that the page exists (response code must equal 200)
$checkPage = new HttpService('www.example.com', 80, '/some/page.html', 200);

// Check page content
$checkPageContent = new HttpService(
    'www.example.com',
    80,
    '/some/page.html',
    200,
    '<title>Hello World</title>'
);

GuzzleHttpService

尝试连接到给定的HTTP主机或IP地址并使用 Guzzle 加载网页。该检查还支持检查响应代码和页面内容。

<?php
use ZendDiagnostics\Check\GuzzleHttpService;

// Try to connect to google.com
$checkGoogle = new GuzzleHttpService('www.google.com');

// Check port 8080 on localhost
$checkLocal = new GuzzleHttpService('127.0.0.1:8080');

// Check that the page exists (response code must equal 200)
$checkPage = new GuzzleHttpService('www.example.com/some/page.html');

// Check page content
$checkPageContent = new GuzzleHttpService(
    'www.example.com/some/page.html',
    array(),
    array(),
    200,
    '<title>Hello World</title>'
);

// Check that the post request returns the content
$checkPageContent = new GuzzleHttpService(
    'www.example.com/user/update',
    array(),
    array(),
    200,
    '{"status":"success"}',
    'POST',
    array("post_field" => "post_value")
);

Memcache

尝试连接到给定的Memcache服务器。

<?php
use ZendDiagnostics\Check\Memcache;

$checkLocal  = new Memcache('127.0.0.1'); // default port
$checkBackup = new Memcache('10.0.30.40', 11212);

PhpVersion

检查当前PHP版本是否符合给定的要求。测试接受2个参数 - 基线版本和可选的 比较运算符

<?php
use ZendDiagnostics\Check\PhpVersion;

$require545orNewer  = new PhpVersion('5.4.5');
$rejectBetaVersions = new PhpVersion('5.5.0', '<');

PhpFlag

确保给定的PHP标志(或标志数组)已启用或禁用(即如php.ini中定义)。您可以使用此测试来提醒用户有关不安全或更改行为的PHP设置。

<?php
use ZendDiagnostics\Check\PhpFlag;

// This check will fail if use_only_cookies is not enabled
$sessionOnlyUsesCookies = new PhpFlag('session.use_only_cookies', true);

// This check will fail if safe_mode has been enabled
$noSafeMode = new PhpFlag('safe_mode', false);

// The following will fail if any of the flags is enabled
$check = new PhpFlag(array(
    'expose_php',
    'ignore_user_abort',
    'html_errors'
), false);

ProcessRunning

检查给定的Unix进程是否正在运行。此检查支持PID和进程名称。

<?php
use ZendDiagnostics\Check\ProcessRunning;

$checkApache = new ProcessRunning('httpd');

$checkProcess1000 = new ProcessRunning(1000);

RabbitMQ

验证RabbitMQ服务是否正在运行。

<?php
use ZendDiagnostics\Check\RabbitMQ;

$rabbitMQCheck = new RabbitMQ('localhost', 5672, 'guest', 'guest', '/');

Redis

验证Redis服务是否正在运行。

<?php
use ZendDiagnostics\Check\Redis;

$redisCheck = new Redis('localhost', 6379, 'secret');

SecurityAdvisory

运行对由 Composer 安装的库的本地安全检查,与 SensioLabs 安全建议数据库 进行比较,并警告潜在的安全漏洞。

<?php
use ZendDiagnostics\Check\SecurityAdvisory;

// Warn about any packages that might have security vulnerabilities and require updating
$security = new SecurityAdvisory();

// Check another composer.lock
$security = new SecurityAdvisory('/var/www/project/composer.lock');

StreamWrapperExists

检查给定的流包装器(或包装器数组)是否可用。例如

<?php
use ZendDiagnostics\Check\StreamWrapperExists;

$checkOGGStream   = new StreamWrapperExists('ogg');
$checkCompression = new StreamWrapperExists(array(
    'zlib',
    'bzip2',
    'zip'
));

DoctrineMigration

确保所有迁移都已应用

<?php
use Doctrine\DBAL\Migrations\Configuration\Configuration;
use Doctrine\ORM\EntityManager;
use ZendDiagnostics\Check\DoctrineMigration;

$em = EntityManager::create(/** config */);
$migrationConfig = new Configuration($em);
$check = new DoctrineMigration($migrationConfig);

IniFile

从给定路径读取INI文件并尝试解析它。

<?php
use ZendDiagnostics\Check\IniFile;

$checkIniFile = new IniFile('/my/path/to/file.ini');
$checkIniFile = new IniFile(['file1.ini', 'file2.ini', '...']);

JsonFile

从给定路径读取JSON文件并尝试解码它。

<?php
use ZendDiagnostics\Check\JsonFile;

$checkJsonFile = new JsonFile('/my/path/to/file.json');
$checkJsonFile = new JsonFile(['file1.json', 'file2.json', '...']);

XmlFile

从给定路径读取XML文件,尝试解析它并尽可能验证它与其DTD模式。

<?php
use ZendDiagnostics\Check\XmlFile;

$checkXmlFile = new XmlFile('/my/path/to/file.xml');
$checkXmlFile = new XmlFile(['file1.xml', 'file2.xml', '...']);

YamlFile

从给定路径读取YAML文件并尝试解析它。

<?php
use ZendDiagnostics\Check\YamlFile;

$checkYamlFile = new YamlFile('/my/path/to/file.yml');
$checkYamlFile = new YamlFile(['file1.yml', 'file2.yml', '...']);