Initial commit
This commit is contained in:
commit
6f4cc23526
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "okawari/job-logging",
|
||||||
|
"description": "Simple dependency for logging information about jobs",
|
||||||
|
"type": "library",
|
||||||
|
"require": {
|
||||||
|
"illuminate/support": "^11.0"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Okawari\\JobLogging\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Tommy Stigen Olsen",
|
||||||
|
"email": "tommysolsen@gmail.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="Okawari\JobLogging" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Okawari\JobLogging;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* App\Models\JobLog
|
||||||
|
*
|
||||||
|
* @property int $id
|
||||||
|
* @property string|null $job_id
|
||||||
|
* @property string $class
|
||||||
|
* @property string $name
|
||||||
|
* @property string|null $owner_type
|
||||||
|
* @property int|null $owner_id
|
||||||
|
* @property bool|null $success
|
||||||
|
* @property string $output
|
||||||
|
* @property \Illuminate\Support\Carbon|null $started_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $ended_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read Model|\Eloquent $owner
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog whereClass($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog whereEndedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog whereJobId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog whereName($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog whereOutput($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog whereOwnerId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog whereOwnerType($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog whereStartedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog whereSuccess($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|JobLog whereUpdatedAt($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class JobLog extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'started_at' => 'datetime',
|
||||||
|
'ended_at' => 'datetime',
|
||||||
|
];
|
||||||
|
protected $fillable = [
|
||||||
|
'job_id',
|
||||||
|
'class',
|
||||||
|
'name',
|
||||||
|
'owner_type',
|
||||||
|
'owner_id',
|
||||||
|
'output',
|
||||||
|
'started_at',
|
||||||
|
'ended_at',
|
||||||
|
'success'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function owner(): MorphTo {
|
||||||
|
return $this->morphTo();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Okawari\JobLogging;
|
||||||
|
|
||||||
|
use App\Contracts\NamedJob;
|
||||||
|
use App\Contracts\OwnedJob;
|
||||||
|
use App\Models\JobLog;
|
||||||
|
use App\Services\JobLogger;
|
||||||
|
use Illuminate\Queue\Events\JobFailed;
|
||||||
|
use Illuminate\Queue\Events\JobProcessed;
|
||||||
|
use Illuminate\Queue\Events\JobProcessing;
|
||||||
|
use Illuminate\Queue\Jobs\SyncJob;
|
||||||
|
use Illuminate\Support\Facades\Event;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class JobLogProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
$driver = Log::getDefaultDriver();
|
||||||
|
|
||||||
|
Event::listen(function (JobProcessing $event) {
|
||||||
|
/** @var \Monolog\Logger $logger */
|
||||||
|
$logger = Log::getLogger();
|
||||||
|
|
||||||
|
$job = $event->job;
|
||||||
|
$owner = $job instanceof OwnedJob ? $job->getOwner() : null;
|
||||||
|
$name = $job instanceof NamedJob ? $job->getJobLogName() : $event->job->getName();
|
||||||
|
|
||||||
|
if ($job instanceof SyncJob) {
|
||||||
|
$job = unserialize(data_get(json_decode($job->getRawBody()), 'data.command'));
|
||||||
|
$owner = $job instanceof OwnedJob ? $job->getOwner() : $owner;
|
||||||
|
$name = $job instanceof NamedJob ? $job->getJobLogName() : $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
$jobLog = app(JobLog::class)::create([
|
||||||
|
'job_id' => $event->job->getJobId() ?: '',
|
||||||
|
'class' => get_class($event->job),
|
||||||
|
'name' => $name,
|
||||||
|
'owner_type' => $owner ? get_class($owner) : null,
|
||||||
|
'owner_id' => $owner?->id,
|
||||||
|
'output' => '',
|
||||||
|
'started_at' => now(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$logger->pushProcessor(new JobLogger($jobLog));
|
||||||
|
});
|
||||||
|
|
||||||
|
Event::listen(function (JobFailed $event) {
|
||||||
|
/** @var \Monolog\Logger $logger */
|
||||||
|
$jobLogger = $this->getJobLogger();
|
||||||
|
|
||||||
|
if (!$jobLogger) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$job = $event->job;
|
||||||
|
$logLine = $jobLogger->log;
|
||||||
|
$owner = $job instanceof OwnedJob ? $job->getOwner() : null;
|
||||||
|
$name = $job instanceof NamedJob ? $job->getJobLogName() : $event->job->getName();
|
||||||
|
if ($owner) $logLine->owner()->associate($owner);
|
||||||
|
if ($name) $logLine->name = $name ?: $logLine->name;
|
||||||
|
|
||||||
|
$logLine->output .= "[EXCEPTION] " . now()->toIso8601ZuluString() . ": {$event->exception->getMessage()}";
|
||||||
|
$success = $event->job?->hasFailed() === false;
|
||||||
|
$logLine->success = $success;
|
||||||
|
$logLine->ended_at = now();
|
||||||
|
$logLine->save();
|
||||||
|
});
|
||||||
|
|
||||||
|
Event::listen(function (JobProcessed|JobFailed $event) {
|
||||||
|
try {
|
||||||
|
/** @var \Monolog\Logger $logger */
|
||||||
|
$jobLogger = $this->getJobLogger();
|
||||||
|
if (!$jobLogger) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$job = $event->job;
|
||||||
|
$logLine = $jobLogger->log;
|
||||||
|
|
||||||
|
$owner = $job instanceof OwnedJob ? $job->getOwner() : null;
|
||||||
|
$name = $job instanceof NamedJob ? $job->getJobLogName() : $event->job->getName();
|
||||||
|
if ($owner) $logLine->owner()->associate($owner);
|
||||||
|
if ($name) $logLine->name = $name ?: $logLine->name;
|
||||||
|
|
||||||
|
$logLine->success = !$event->job->hasFailed();
|
||||||
|
$logLine->ended_at = now();
|
||||||
|
$logLine->save();
|
||||||
|
} catch (\Throwable $t) {
|
||||||
|
dd($t, debug_backtrace());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getJobLogger(): ?JobLogger
|
||||||
|
{
|
||||||
|
$logger = Log::driver()->getLogger();
|
||||||
|
$jobLogger = $logger->popProcessor();
|
||||||
|
if ($jobLogger instanceof JobLogger) {
|
||||||
|
return $jobLogger;
|
||||||
|
} else {
|
||||||
|
$logger->pushProcessor($jobLogger);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Okawari\JobLogging;
|
||||||
|
|
||||||
|
use App\Models\JobLog;
|
||||||
|
use Monolog\LogRecord;
|
||||||
|
use Monolog\Processor\ProcessorInterface;
|
||||||
|
|
||||||
|
class JobProcessor implements ProcessorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct(public JobLog $log)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(LogRecord $record)
|
||||||
|
{
|
||||||
|
$line = "[{$record->level->getName()}] $record->datetime: $record->message";
|
||||||
|
$this->log->output = "{$this->log->output}$line\r\n";
|
||||||
|
return $record;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue