Core - v1.2.0
Logging
Every ArtisanPack UI package routes its log messages through the same logging stack so an application owner can filter, aggregate, and forward those messages from a single place. The stack consists of:
ArtisanPackLogger— the interface every package logger implementsLogger— the default implementation backed by Laravel'sLogManagerLoggerFactory— a container singleton that caches oneLoggerper packageArtisanPackLog— the static facade for the factoryAuditLogCreated— the event emitted by$log->audit()calls
Resolution
Resolve a logger scoped to your package via the facade, the helper, or container injection:
use ArtisanPackUI\Core\Facades\ArtisanPackLog;
use ArtisanPackUI\Core\Logging\LoggerFactory;
$log = ArtisanPackLog::make( 'media-library' );
// Or
$log = app( LoggerFactory::class )->make( 'media-library' );
// Or inject directly
public function __construct( protected LoggerFactory $loggers ) {}
$log = $this->loggers->make( 'media-library' );
The factory caches one logger per package — calling make() multiple times returns the same instance.
Writing entries
The four PSR-3 severities every package implementation emits:
$log->debug( 'Processing thumbnail.', [ 'media_id' => 42 ] );
$log->info( 'Image uploaded.', [ 'media_id' => 42, 'size' => '1.2 MB' ] );
$log->warning( 'Slow transcode.', [ 'media_id' => 42, 'duration_ms' => 2400 ] );
$log->error( 'Transcode failed.', [ 'media_id' => 42, 'reason' => 'unsupported codec' ] );
Every entry is automatically prefixed with the owning package's short name so aggregated streams can be filtered cleanly:
[2026-05-23 14:32:09] local.INFO: [media-library] Image uploaded. {"media_id":42,"size":"1.2 MB"}
Audit entries
audit() is for compliance-relevant or security-relevant actions. It writes an [AUDIT] prefixed info-level entry AND dispatches an AuditLogCreated event with structured metadata:
$log->audit( 'media.deleted', [
'media_id' => 42,
'reason' => 'user_request',
] );
The dispatched event payload includes:
package— the owning package's short nameaction— the action identifier (e.g.media.deleted)data— the caller-supplied arrayuser_id— the resolved actor identifier (fromauth()by default)ip_address— the resolved request IP (fromrequest()by default)timestamp— UTC ISO 8601 timestamp
Listening for audit events
Applications listen for AuditLogCreated to persist records, forward them to an external aggregator (Elasticsearch, Datadog, Splunk), or trigger notifications:
use ArtisanPackUI\Core\Events\AuditLogCreated;
use Illuminate\Support\Facades\Event;
Event::listen( AuditLogCreated::class, function ( AuditLogCreated $event ): void {
AuditEntry::create( [
'package' => $event->data['package'],
'action' => $event->data['action'],
'data' => $event->data['data'],
'user_id' => $event->data['user_id'],
'ip_address' => $event->data['ip_address'],
'occurred_at' => $event->data['timestamp'],
] );
} );
Disabling audit logging
Set artisanpack.core.logging.audit.enabled = false in config/artisanpack.php (or ARTISANPACK_AUDIT_ENABLED=false in your .env if the binding is wired up) to silently drop audit() calls. Useful for environments that should not record audit log noise.
Choosing a log channel
Set artisanpack.core.logging.channel (or the ARTISANPACK_LOG_CHANNEL env var) to the name of a Laravel log channel defined in config/logging.php to route every ArtisanPack UI entry through that channel:
// config/logging.php
'channels' => [
'artisanpack' => [
'driver' => 'daily',
'path' => storage_path( 'logs/artisanpack.log' ),
'days' => 14,
],
],
// config/artisanpack.php
'core' => [
'logging' => [
'channel' => 'artisanpack',
],
],
Leaving the channel as null (the default) falls back to Laravel's default channel.
Custom actor / request resolvers
The default Logger resolves the actor identifier via auth()->id() and the IP via request()->ip(). Console commands, queue workers, and background jobs may not have an authenticated user or an HTTP request available — in those contexts you can construct a logger with your own resolver closures:
use ArtisanPackUI\Core\Logging\Logger;
$log = new Logger(
package: 'media-library',
logManager: app( \Illuminate\Log\LogManager::class ),
dispatcher: app( \Illuminate\Contracts\Events\Dispatcher::class ),
channel: 'artisanpack',
auditEnabled: true,
actorResolver: fn () => 'cli:thumbnail-generator',
requestResolver: fn () => gethostbyname( gethostname() ),
);
In ordinary HTTP request handling, prefer the factory — it caches loggers, applies the configured channel + audit settings, and uses the default auth() / request() resolvers.
Facade method map
| Facade method | Factory method |
|---|---|
ArtisanPackLog::make( $package ) |
LoggerFactory::make() |
ArtisanPackLog::has( $package ) |
LoggerFactory::has() |
ArtisanPackLog::forget( ?$package = null ) |
LoggerFactory::forget() |
ArtisanPackLog::all() |
LoggerFactory::all() |