Table of Contents
- Provide
Analyzer
that can measure the amount of time and memory of blocks of code - Report measured amount through file or console
- Support multiple Profile for multiple metrics
For example, you can do this:
// Start of code
$uid = Analyzer::start("Do a simple math");
// Calculating
$output = 1 + 1;
// Print output to screen
echo $output;
// End of code
Analyzer::stop($uid);
// Flush to get report
Analyzer::flush();
After that, you will get a report like this
Default --------------------
╭───────────────┬──────────────────┬─────────────┬────────┬────────────┬────────────┬───────────╮
│ Uid │ Name │ Time │ Memory │ Start peak │ Stop peak │ Diff peak │
├───────────────┼──────────────────┼─────────────┼────────┼────────────┼────────────┼───────────┤
│ 654af62889e08 │ Do a simple math │ 2006.472 ms │ 2.5 KB │ 16502872 B │ 16502872 B │ 0 B │
╰───────────────┴──────────────────┴─────────────┴────────┴────────────┴────────────┴───────────╯
----------------------------
The report can be printed to file or console. Moreover, you can decide to grab the report result and print it to wherever you want
Run script to install
composer require --dev duckstery/process-analyzer
Warning
This integration only work properly while handling request individually (1 request at a time) because it'll flush everything out at the end of the request.
Run script to install
composer require --dev duckstery/laravel-process-analyzer
Package's ServiceProvider will be auto required by Laravel. If you don't use auto-discovery, you need to manually add ServiceProvider
Duckstery\Laravel\Analyzer\ProcessAnalyzerServiceProvider::class
to the providers array in config/app.php
/*
|--------------------------------------------------------------------------
| Autoloaded Service Providers
|--------------------------------------------------------------------------
|
| The service providers listed here will be automatically loaded on the
| request to your application. Feel free to add your own services to
| this array to grant expanded functionality to your applications.
|
*/
'providers' => ServiceProvider::defaultProviders()->merge([
/*
* Package Service Providers...
*/
Duckstery\Laravel\Analyzer\ProcessAnalyzerServiceProvider::class, // ** //
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
])->toArray(),
Then, you can publish config file for better customization
php artisan vendor:publish --provider="Duckstery\Laravel\Analyzer\ProcessAnalyzerServiceProvider"
Before use, you should config package to match your needs.
To config, create a class and extend AnalyzerConfig
like this
<?php
use Duckstery\Analyzer\AnalyzerConfig;
class MyAnalyzerConfig extends AnalyzerConfig
{
// Todo
}
Then, you can override AnalyzerConfig
's properties or functions and change their value
<?php
use Duckstery\Analyzer\AnalyzerConfig;
class MyAnalyzerConfig extends AnalyzerConfig
{
// Property override
protected bool $prettyPrint;
// Function override
public function prettyPrint(): bool
{
return true;
}
}
Beware that config with function override will ignore the property's value. If you config logic is big, you should use function override instead.
After creating config class, init Analyzer
with your class's instance
<?php
use Duckstery\Analyzer\Analyzer;
Analyzer::tryToInit(new MyAnalyzerConfig());
enable
: This option will enable and disable Analyzer
. With this option, you can include this package in
production. If you need it to measure your process in production, you can switch it on. But remember to switch it off
after
- Type:
bool
- Default: true
defaultProfile
: Define default Profile name
- Type:
string
- Default: "Default"
defaultRecordGetter
: Define getter method name. This method will return Record's default name
- Type:
array
|string
|null
- Default:
profileExtras
: Define extra metrics for Profile. These metrics can be retrieved at the start or end of execution.
After that, Analyzer
can calculate difference or format them
- Type:
array
- Default:
[
"Default" => [
"peak" => [
// Metrics method name's or callback array
"handler" => "memory_get_peak_usage",
// Formatter
"formatter" => [Utils::class, "appendB"],
// Get at the start
"start" => true,
// Get at the end
"stop" => true,
// Calculate difference
"diff" => true
]
]
]
profile
: Profile class. You can customize by create a new class that extend IAProfile
- Type:
string
- Default:
Duckstery\Analyzer\Structures\AnalysisProfile::class
record
: Record class
- Type:
string
- Default:
Duckstery\Analyzer\Structures\AnalysisRecord::class
printer
: Printer class
- Type:
string
- Default:
Duckstery\Analyzer\AnalysisPrinter::class
prettyPrint
: Print report in table
- Type:
bool
- Default: true
- Example:
$prettyPrint = true;
// Default --------------------
// ╭───────────────┬──────────────────┬─────────────┬────────┬────────────┬────────────┬───────────╮
// │ Uid │ Name │ Time │ Memory │ Start peak │ Stop peak │ Diff peak │
// ├───────────────┼──────────────────┼─────────────┼────────┼────────────┼────────────┼───────────┤
// │ 654af62889e08 │ Do a simple math │ 2006.472 ms │ 2.5 KB │ 16502872 B │ 16502872 B │ 0 B │
// ╰───────────────┴──────────────────┴─────────────┴────────┴────────────┴────────────┴───────────╯
// ----------------------------
$prettyPrint = false;
// Default --------------------
// [654af6159585c] Do a simple math:
// Time ⇒ [2000.605 ms];
// Memory ⇒ [2.5 KB];
// Start peak ⇒ [16501872 B];
// Stop peak ⇒ [16501872 B];
// Diff peak ⇒ [0 B];
// ----------------------------
oneLine
: Print each Record in report in a line. Ignored if prettyPrint
: true
- Type:
bool
- Default:
- Example:
$oneLine = true;
// Default --------------------
// [654b2b522090f] Do a simple math: Time ⇒ [2009.288 ms]; Memory ⇒ [2.5 KB]; Start peak ⇒ [16501904 B]; Stop peak ⇒ [16501904 B]; Diff peak ⇒ [0 B];
// ----------------------------
$oneLine = false;
// Default --------------------
// [654af6159585c] Do a simple math:
// Time ⇒ [2000.605 ms];
// Memory ⇒ [2.5 KB];
// Start peak ⇒ [16501872 B];
// Stop peak ⇒ [16501872 B];
// Diff peak ⇒ [0 B];
// ----------------------------
showUID
: Show Record's UID in report
- Type:
bool
- Default: true
useFile
: Define path to directory that holds report file. Report file will be created each day. If useFile
is false, report won't be printed to any file
- Type:
string
- Default: "logs"
useConsole
: Print result to console. If useConsole
is false, report won't be printed to console
- Type:
bool
- Default: true
profilePrefix
: Define Profile's name prefix
- Type:
string
- Default: ""
profileSuffix
: Define Profile's name suffix
- Type:
string
- Default: ""
recordPrefix
: Define Record's name prefix
- Type:
string
- Default: ""
recordSuffix
: Define Record's suffix
- Type:
string
- Default: ""
timeUnit
: Define unit of time
- Type:
string
- Default: "ms"
timeFormatter
: Define a callback to modify main time metrics. Ignored timeUnit
if this option is defined
- Type:
array
|string
|null
- Default: null
memUnit
: Define unit of memory
- Type:
string
- Default: "KB"
memFormatter
: Define a callback to modify main memory metrics. Ignored memUnit
if this option is defined
- Type:
array
|string
|null
- Default:
topLeftChar
: Define top left corner character
- Type:
string
- Default: "╭"
topRightChar
: Define top right corner character
- Type:
string
- Default: "╮"
bottomLeftChar
: Define bottom left corner character
- Type:
string
- Default: "╰"
bottomRightChar
: Define bottom right corner character
- Type:
string
- Default: "╯"
topForkChar
: Define top fork character
- Type:
string
- Default: "┬"
rightForkChar
: Define right fork character
- Type:
string
- Default: "┤"
bottomForkChar
: Define bottom fork character
- Type:
string
- Default: "┴"
leftForkChar
: Define left fork character
- Type:
string
- Default: "├"
crossChar
: Define cross character
- Type:
string
- Default: "┼"
There are some printer's hooks that allow you to interact with report data. To use these hooks, create a class and
extend AnalysisPrinter
Duckstery\Analyzer\AnalysisPrinter::class
Then, override methods like this
<?php
use Duckstery\Analyzer\AnalysisPrinter;
use Duckstery\Analyzer\Interfaces\IAProfile;
class MyPrinter extends AnalysisPrinter
{
public function onPreprocessProfile(IAProfile $profile): void
{
// Todo
}
}
These are some hooks that you can use:
onPreprocessProfile
: Execute before process Profile
- Param:
IAProfile
: Profile can be modified at this hook
onPreprocessRecord
: Execute on each Record and before process Record
- Param:
IARecord
: Record can be modified at this hook
onEachPreprocessedRecord
: Execute on each Record and after process Record
- Param:
array
- Example: Without Profile's extras
$example = [
"uid" => "654af6159585c",
"name" => "handle",
"time" => "2000.605 ms",
"memory" => "2.5 KB",
]
- Example: With Profile's extras (peak)
$example = [
"uid" => "654af6159585c",
"name" => "handle",
"time" => "2000.605 ms",
"memory" => "2.5 KB",
"start peak" => ..., // If start = true
"stop peak" => ..., // If stop = true
"diff peak" => ..., // If start = stop = diff = true
]
onEachRecordString
: Execute on each Record and after convert Record to string
- Param:
string
onPrintProfileString
: Execute after complete the report
- Param:
string
: This is the final report - Note: Modify this won't change your file or console result. If you want to send your report elsewhere, you should
disable
useFile
anduseConsole
and define your logic in this hook instead.
These are some examples to instruct you to use this package. You will be provided with a static class.
Duckstery\Analyzer\Analyzer::class
Analyzer
will only measure execution time and memory of your execution. It'll exclude self execution time and
memory out of final result.
The basic approach is placing your logic inside start
and stop
. When everything is done, call flush
so Analyzer can generate the report for you.
The Laravel integration has a specific middleware that will execute flush
at the end of request. So you don't need to flush
while using that integration. But in most case, you have to flush
at the end of your program (or at least at the end of the process that you desired to measure).
For any unmentioned situation, you can issue me for more detail.
Analyzer
only measure execution time and memory of your execution
<?php
use Duckstery\Analyzer\Analyzer;
public class SomeController
{
public function handle(): void
{
// Use Profile: SomeController and start recording
Analyzer::profile("SomeController")->start("handle");
// Execute process A
$this->processA();
// Execute process B
$this->processB();
// Execute process C
$this->processC();
// Stop the latest recording of Profile
Analyzer::profile("SomeController")->stop();
// Flush
Analyzer::flush("SomeController");
// Or Analyzer::flush(); to flush all Profile
}
public function processA(): void
{
// Use Profile: SomeController and start recording
Analyzer::profile("SomeController")->start("processA");
// Use 5kb
// Stop the latest recording of Profile
Analyzer::profile("SomeController")->stop();
}
public function processB(): void
{
// Use Profile: SomeController and start recording
Analyzer::profile("SomeController")->start("processA");
// Use 0kb
// Stop the latest recording of Profile
Analyzer::profile("SomeController")->stop();
}
public function processC(): void
{
// Use Profile: SomeController and start recording
Analyzer::profile("SomeController")->start("processA");
// Executed for 5s
// Stop the latest recording of Profile
Analyzer::profile("SomeController")->stop();
}
}
Report
SomeController --------------------
╭───────────────┬──────────┬─────────────┬────────╮
│ Uid │ Name │ Time │ Memory │
├───────────────┼──────────┼─────────────┼────────┤
│ 654af62889e08 │ handle │ 5036.472 ms │ 5 KB │
│ 654af62889e09 │ processA │ 6.472 ms │ 0 KB │
│ 654af62889e10 │ processB │ 6.472 ms │ 5 KB │
│ 654af62889e11 │ processC │ 5000.472 ms │ 0 KB │
╰───────────────┴──────────┴─────────────┴────────╯
------------------------------
Config
$profileExtras = [
"Default" => [
"peak" => [
// Metrics method name's or callback array
"handler" => "memory_get_peak_usage",
// Formatter
"formatter" => [Utils::class, "appendB"],
// Get at the start
"start" => true,
// Get at the end
"stop" => true,
// Calculate difference
"diff" => true
]
]
]
Capture metrics by using default Profile
<?php
use Duckstery\Analyzer\Analyzer;
public class SomeController
{
public function handle(): void
{
$uid = Analyzer::start("SomeController::handle");
// Or Analyzer::start("SomeController::handle");
// Todo
Analyzer::stop($uid);
// Or Analyzer::stop();
// Flush
Analyzer::flush();
}
}
Report
Default --------------------
╭───────────────┬────────────────────────┬─────────────┬────────┬────────────┬────────────┬───────────╮
│ Uid │ Name │ Time │ Memory │ Start peak │ Stop peak │ Diff peak │
├───────────────┼────────────────────────┼─────────────┼────────┼────────────┼────────────┼───────────┤
│ 654af62889e08 │ SomeController::handle │ 2006.472 ms │ 0 KB │ 16502872 B │ 16502872 B │ 0 B │
╰───────────────┴────────────────────────┴─────────────┴────────┴────────────┴────────────┴───────────╯
----------------------------
Capture metrics by using default Record name
<?php
use Duckstery\Analyzer\Analyzer;
public class SomeController
{
public function handle(): void
{
$uid = Analyzer::start();
// Or Analyzer::start();
// Todo
Analyzer::stop($uid);
// Or Analyzer::stop();
// Flush
Analyzer::flush();
}
}
Report
Default --------------------
╭───────────────┬──────────────────┬─────────────┬────────┬────────────┬────────────┬───────────╮
│ Uid │ Name │ Time │ Memory │ Start peak │ Stop peak │ Diff peak │
├───────────────┼──────────────────┼─────────────┼────────┼────────────┼────────────┼───────────┤
│ 654af62889e08 │ Function: handle │ 2006.472 ms │ 0 KB │ 16502872 B │ 16502872 B │ 0 B │
╰───────────────┴──────────────────┴─────────────┴────────┴────────────┴────────────┴───────────╯
----------------------------
Capture metrics with multiple Profile
<?php
use Duckstery\Analyzer\Analyzer;
public class SomeController
{
public function handle(): void
{
$uid = Analyzer::startProfile("Profile 1");
// Or Analyzer::startProfile("Profile 1");
$this->todo();
Analyzer::stopProfile("Profile 1", $uid);
// Or Analyzer::stopProfile("Profile 1");
// Flush
Analyzer::flush();
}
public function todo(): void
{
$uid = Analyzer::startProfile("Profile 2");
// Or Analyzer::startProfile("Profile 2");
$this->todo();
Analyzer::stopProfile("Profile 2", $uid);
// Or Analyzer::stopProfile("Profile 2");
}
}
Report
Profile 1 --------------------
╭───────────────┬──────────────────┬─────────────┬────────╮
│ Uid │ Name │ Time │ Memory │
├───────────────┼──────────────────┼─────────────┼────────┤
│ 654af62889e08 │ Function: handle │ 2006.472 ms │ 0 KB │
╰───────────────┴──────────────────┴─────────────┴────────╯
------------------------------
Profile 2 --------------------
╭───────────────┬────────────────┬─────────────┬────────╮
│ Uid │ Name │ Time │ Memory │
├───────────────┼────────────────┼─────────────┼────────┤
│ 654af62889e09 │ Function: todo │ 2006.472 ms │ 0 KB │
╰───────────────┴────────────────┴─────────────┴────────╯
------------------------------
For testing
composer run-script test
For coverage
composer run-script test-coverage
If you discover any security-related issues, bugs or ideas, please feel free to create an issue.
The MIT License (MIT). Please see License File for more information.