caseyamcl / tasktracker
一个用于跟踪长时间运行的任务进度和统计信息的PHP库
Requires
- php: >=5.4|^7.0
- symfony/event-dispatcher: ^2.6|^3.0|^4.0
Requires (Dev)
- mockery/mockery: ^0.9
- monolog/monolog: ^1.13
- phpunit/phpunit: ^4.0
- psr/log: ^1.0
- symfony/console: ^2.6|^3.0|^4.0
README
一个用于在PHP中跟踪长时间运行任务的库(当简单的进度条不够用时)
快速浏览:
- 在长时间运行的任务期间报告内存使用情况和多个进度统计信息
- 适用于执行大量小型作业的长时间运行过程
- 使用 Symfony Event-Dispatcher Component 的事件驱动架构
- 可以向任何 EventSubscriberInterface 报告任务进度
- 提供用于报告任务进度的内置实用工具
- Symfony控制台进度条
- Symfony控制台任务消息运行日志
- 将任务进度发送到PSR-3兼容的日志记录器
例如,您可能希望在任务执行期间在控制台上显示进度条,同时将系统状态的周期性快照发送到Monolog。使用单个Tracker对象,您可以同时实现这两个目标
use TaskTracker\Tracker, TaskTracker\Tick; use TaskTracker\Subscriber\SymfonyConsoleProgress, TaskTracker\Subscriber\Psr3Logger; use Symfony\Console\Output\ConsoleOutput; use Monolog\Logger as MonologLogger; // Setup subscribers $subscribers = [ new SymfonyConsoleProgress(new ConsoleOutput()), new Psr3Logger(new MonologLogger()) ]; // Setup a tracker for a job with 100 items $tracker = Tracker::build(100, $subscribers); $tracker->start("Let's go"); for ($i = 0; $i < 100; $i++) { // Do some work of some sort... $tracker->tick(); } $tracker->finish("All done");
安装
通过Composer安装
composer require caseyamcl/tasktracker:~2.0
手动安装
- 从http://github.com/caseyamcl/tasktracker下载源码。
- 使用PSR-4兼容的自动加载器将
src/TaskTracker
文件夹包含到您的代码中。
使用方法
要跟踪任务,创建Tracker
类的实例
use TaskTracker\Tracker;
// Instantiate a tracker to track 100 items
$tracker = new Tracker(100);
如果您正在处理未知数量的项目,可以省略项目数量
$tracker = new Tracker();
Tracker
类会创建自己的EventDispatcher
,但您可以可选地注入自己的实例
$dispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher();
$tracker = new Tracker(100, $dispatcher);
// ..or..
$tracker = new Tracker(Tracker::UNKNOWN, $dispatcher);
要开始跟踪,只需调用Tracker::start()
方法
// Start the tracker
$tracker->start('optional starting message');
对于您处理的每个元素,调用Tracker::tick()
方法,直到完成
// Tick
$tracker->tick();
有三种类型的Tick:成功(默认)、失败和跳过
use Tracker\Tick;
$tracker->tick(Tick::SUCCESS);
$tracker->tick(Tick::FAIL);
$tracker->tick(Tick::SKIP);
您还可以提供可选的消息
$tracker->tick(Tick::SUCCESS, 'Things are going well.');
$tracker->tick(Tick::FAIL, 'Crud. Something went wrong');
$tracker->tick(Tick::SKIP, 'Skipping this record for whatever reason');
您可以将自定义数据作为数组添加到Tick中
$tracker->tick(Tick::SUCCESS, 'Things are going well.', ['foo' => 'bar', 'baz' => 'biz]);
并且,您可以一次递增多个项目
// Increment by 5 items
$tracker->tick(Tick::SUCCESS, '', [], 5);
// Three items failed
$tracker->tick(Tick::FAIL, 'Something went wrong', [], 3);
完成时,调用Tracker::finish()
方法
$tracker->finish('Optional finish manage');
或者,如果在处理过程中出现问题,可以中止
$tracker->abort('Optional abort message');
类还包含一些辅助方法
// Have we started processing yet?
$tracker->isRunning();
// Get the last tick (instance of \Tracker\Tick class)
$tracker->getLastTick();
// Get the status of the process as an int (Tracker::NOT_STARTED, Tracker::RUNNING, Tracker::FINISHED, or Tracker::ABORTED)
$tracker->getStatus();
// Get the number of items processed thus far
$tracker->getNumProcessedItems();
// Get only the number of failed items (works with SUCCESS and SKIP too)
$tracker->getNumProcessedItems(Tick::FAIL);
// Get the time started (in microseconds)
$tracker->getStartTime();
您可以使用Tracker:run($iterator, $callback)
方法获得更简洁的语法。$iterator
值必须是\Traversable
的实例;数组不接受,但ArrayIterator
对象将工作
$iterator = new \ArrayIterator(['a', 'b', 'c']);
// This code is the equivalent of...
$tracker->run($iterator, function(Tracker $tracker, $item) {
// work on a single item
$tracker->tick();
});
//...this code:
$tracker->start();
foreach ($iterator as $item) {
// work on a single item
$tracker->tick();
}
$tracker->finish();
订阅者
没有事件订阅者来监听跟踪器tick事件,Tracker
类本身并不很有用。此库附带了一些订阅者
TaskTracker\Subscriber\Psr3Logger
- 将跟踪器事件记录到任何PSR-3 Logger
TaskTracker\Subscriber\SymfonyConsoleLog
- 将跟踪器事件记录到Symfony控制台,每个事件占一行。TaskTracker\Subscriber\SymfonyConsoleProgress
- 将跟踪器事件记录到Symfony控制台进度条指示器。
您可以通过调用Tracker::addSubscriber()
方法将事件订阅者添加到跟踪器
$tacker = new Tracker(100);
$tracker->addSubscriber(new SymfonyConsoleLog($output));
如果您提前知道将要使用的订阅者,可以使用Tracker::build()
方法来方便操作
$subscribers = [new SymfonyConsoleLog($output), new SomeOtherSubscriber()];
$tracker = Tracker::build(100, $subscribers);
示例
例如,假设您正在创建一个Symfony控制台命令,并希望为某个任务显示进度条,同时记录事件
use TaskTracker\Tracker; use TaskTracker\Tick; use TaskTracker\Subscriber\SymfonyConsoleProgress; use Symfony\Component\Console\Command\Command; /** * My Symfony Command */ class MyCommand extends Command { protected function configure() { $this->setName('example'); $this->setDescription("Demonstrate TaskTracker"); } protected function execute(InputInterface $input, OutputInterface $output) { $numItems = 10; // Build Task Tracker with Symfony Console Progress Bar subscriber $tracker = Tracker::build([new SymfonyConsoleProgress($output)], $numItems); // Add a Monolog Listener after Tracker construction $monolog = new \Monolog\Logger(/* some handlers */); $tracker->addSubscriber(new Psr3Logger($monolog)); // You can also add Event Listeners directly $tracker->getDispatcher()->addListener(\Tracker\Events::TRACKER_TICK, function(\Tracker\Tick $tick) { // do something... }); // Tracker::start() is technically optional; if not called, it will automatically // be called upon the first Tick $tracker->start("Let's go!"); // The SymfonyConsoleProgress listener will output a progress bar while the logger will log events for ($i = 0; $i < 10; $i++) { $tracker->tick(\Tick::SUCCESS, "On item: " . $i); sleep(1); } // Tracker::start(), Tracker::tick(), Tracker::abort(), and Tracker::finish() all return // a \Tracker\Report object. $report = $tracker->finish('All done!'); $output->writeln(sprintf("All Done! <info>%s</info> items processed", $report->getNumTotalItems())); } }
自定义订阅者
TaskTracker使用了Symfony EventDispatcher库,因此任何兼容Symfony的事件监听器都可以使用。
您可以监听以下四个事件
TaskTracker\Events::TRACKER_START
TaskTracker\Events::TRACKER_TICK
TaskTracker\Events::TRACKER_FINISH
TaskTracker\Events::TRACKER_ABORT
所有四个事件都会分发一个TaskTracker\Tick
类的实例。您的订阅者/监听器应该接受该类的对象作为参数
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use TaskTracker\Tick; /** * Listen for Tracker Events */ class MyEventSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents() { return [ TaskTracker\Events::TRACKER_START => 'handle', TaskTracker\Events::TRACKER_TICK => 'handle', TaskTracker\Events::TRACKER_FINISH => 'handle', ]; } public static function handle(Tick $tickEvent) { // See all of the information about the progress of that tick var_dump($tickEvent->getReport()->toArray()); } }
报告
每个Tracker事件都会发射一个携带过程快照和一些系统信息的\Tracker\Report
对象,这些信息是在事件发生的时间点存在的。
$report = $tracker->tick(); $report->getTimeStarted(); $report->getTotalItemCount(); $report->getTick(); $report->getNumItemsProcessed(); $report->getTimeElapsed(); $report->getNumItemsSuccess(); $report->getNumItemsFail(); $report->getNumItemsSkip(); $report->getItemTime(); $report->getMaxItemTime(); $report->getMinItemTime(); $report->getAvgItemTime(); $report->getMemUsage(); $report->getMemPeakUsage(); $report->getMessage(); $report->getTimestamp(); $report->getStatus(); $report->getIncrementBy(); $report->getReport(); $report->getExtraInfo();
在您的订阅者中,您可以通过调用Tick::getReport()
从Tick
对象中访问报告。