Reputation: 199
THE GOAL: When specific commands are executed - either through me manually running via the app server's CLI and/or through the app's code itself - to log to a MySQL Db the name of the Artisan
command, the time it took to run, etc.
MY APPROACH: Create an abstract LogCommandClass
that extends Command
and implements a LogCommandInterface
which contains a single method, LogCommandToDb()
. Then, have the 'desired-to-be-logged' Artisan
command classes extend LogCommandClass
.
THE ISSUE: Only when I actually type in a command via CLI on our server (ex. php artisan some-command
) does the command get logged to Db. Commands that are called within the code via Artisan::call('some-command')
do not get logged, but they need to be as well!
My only remaining approach is to replace within the code all instances of Artisan::call('some-command')
with something like,
$string ="cd ".base_path(). " && php artisan some-command";
shell_exec($string);
but that doesn't seem ideal...
LogCommandClass.php
abstract class LogCommandClass extends Command implements LogCommandInterface {
protected $commName, $startTime, $endTime;
/**
* @return void
*/
public function __construct()
{
parent::__construct();
$this->startTime = (new DateTime())->getTimestamp();
}
/**
* @return void
*/
public function __destruct()
{
if (Arr::get(request()->server(), 'argv.1') == $this->getName()) {
$this->LogCommandToDb();
}
}
public function LogCommandToDb() {
$this->endTime = (new DateTime())->getTimestamp();
$diff = $this->endTime - $this->startTime;
$comm = new CommandLog;
$comm->LogCommand($this->getName(), $diff);
}
}
LogCommandInterface.php
interface LogCommandInterface
{
public function LogCommandToDb();
}
SomeCommandClass.php
class SomeCommandClass extends LogCommandClass {
/**
* The console command name.
*
* @var string
*/
protected $name = 'some-command';
/**
* The console command description.
*
* @var string
*/
protected $description = 'A command that should be logged to Db.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct() {
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle() {
//do something
}
CommandLog.php
class CommandLog extends Model {
protected $table = 'CommandLog';
public $timestamps = true;
public function LogCommand($name, $time)
{
$this->commandName = $name;
$this->timeElapsed = $time;
$this->save();
}
}
Upvotes: 0
Views: 966
Reputation: 1134
Each time a command run laravel dispatch Artisan events,
log with the event, I just give it a try and I'm getting both.
At different stages of the command running a event of one of that three types is dispatch. You can set a listener waiting for one.
First, you create your listener
php artisan make:listener CommandStartingLoggin --event=CommandStarting
This will create a class CommandStartingLoggin
in app/Listeners
that class will be called when in this case a command is starting.
But first, for that you need to let laravel know this, in the provider's folder, you'll see EventServiceProvider
in the listen
array to add the entry:
\Illuminate\Console\Events\CommandStarting::class => [
\App\Listeners\CommandStartingLoggin::class,
],
Finally in app/Listeners/CommandStartingLoggin
you'll see a handle
method, you can log there.
Upvotes: 3