Every two weeks I send out a newsletter containing lots of interesting stuff for the modern PHP developer. You can expect quick tips, links to interesting tutorials, opinions and packages. Want to learn the cool stuff? Then sign up now!

A package to log activity in a Laravel app

In your apps there’s probably a lot going on. Users log in and out, they create, update and delete content, mails get sent and so on. For an administrator of an app these events provide useful insights. In almost every project we make at Spatie we log these events and show them in the admin-section of our site. Here’s how that looks like in our Laravel template called Blender.


We made a new package called laravel-activitylog that makes logging activities in a Laravel app a cinch. In this blogpost I’d like to walk you through it.

Basic logging

This is the most basic way to log some activity:

activity()->log('Look mum, I logged something');

This will write a record in the activity_log table. You can retrieve activity using the Spatie\Activitylog\Models\Activity model that the package provides.

$lastActivity = Activity::all()->last(); //returns the last logged activity

$lastActivity->description; //returns 'Look mum, I logged something';

You can specify on which object the activity is performed by using performedOn:


$lastActivity = Activity::all()->last(); //returns the last logged activity

$lastActivity->subject; //returns the model that was passed to `performedOn`;

You can set who or what caused the activity by using causedBy:


$lastActivity = Activity::all()->last(); //returns the last logged activity

$lastActivity->causer; //returns the model that was passed to `causedBy`;   

If you’re not using causedBy the package will automatically use the logged in user.

Automatic model event logging

A neat feature of this package is that it can automatically log events such as when a model is created, updated and deleted. To make this work all you need to do is let your model use the Spatie\Activitylog\Traits\LogsActivity-trait.

As a bonus the package will also log the changed attributes for all these events when setting $logAttributes property on the model.

Here’s an example:

use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;

class NewsItem extends Model
    use LogsActivity;

    protected $fillable = ['name', 'text'];

    protected static $logAttributes = ['name', 'text'];

Let’s see what gets logged when creating an instance of that model.

$newsItem = NewsItem::create([
   'name' => 'original name',
   'text' => 'Lorum'

//creating the newsItem will cause an activity being logged
$activity = Activity::all()->last();

$activity->description; //returns 'created'
$activity->subject; //returns the instance of NewsItem that was created
$activity->changes; //returns ['attributes' => ['name' => 'original name', 'text' => 'Lorum']];

Now let’s update some that $newsItem.

$newsItem->name = 'updated name'

//updating the newsItem will cause an activity being logged
$activity = Activity::all()->last();

$activity->description; //returns 'updated'
$activity->subject; //returns the instance of NewsItem that was created

Calling $activity->changes will return this array:

   'attributes' => [
        'name' => 'original name',
        'text' => 'Lorum',
    'old' => [
        'name' => 'updated name',
        'text' => 'Lorum',

Pretty cool, right?

Now, what happens when you call delete?


//deleting the newsItem will cause an activity being logged
$activity = Activity::all()->last();

$activity->description; //returns 'deleted'
$activity->changes; //returns ['attributes' => ['name' => 'updated name', 'text' => 'Lorum']];

Read the documentation on event logging to learn how to choose the events that must be logged, how to customize the description for an event, and how to specify the attributes of which the changes must be logged.

Using multiple logs

When not specify a log name the activities will be logged on the default log.


$lastActivity = Spatie\Activitylog\Models\Activity::all()->last();

$lastActivity->log_name; //returns 'default', this value can be changed in the config file ;

You can specify the log on which an activity must be logged by passing the log name to the activity function:


Activity::all()->last()->log_name; //returns 'other-log';

Like mentioned before Activity model is just a regular Eloquent model that you know and love. So you can just use a where on it.

Activity::where('log_name' , 'other-log')->get(); //returns all activity from the 'other-log'

The package also provides an inLog scope you can use:


//you can pass multiple log names to the scope
Activity::inLog('default', 'other-log')->get();

//passing an array is just as good
Activity::inLog(['default', 'other-log'])->get();

This concludes the tour of laravel-activitylog. Want to know more about the package, then head over to the documentation to learn all the options. If you find this package useful, be sure to take a look at the Laravel packages we previous made.

Freek Van der Herten is a partner and developer at Spatie, an Antwerp based company that specializes in creating web apps with Laravel. After hours he writes about modern PHP and Laravel on this blog. When not coding he’s probably rehearsing with his kraut rock band.
  • yocmen

    Excellent job!!!! this is awoseme!!!! this is compatible with L 5.1????

    • deductionmaster

      Yes, you can try it.

  • Tihomir Opacic

    As always, only the best from you Freek 🙂 This is something that we’ll try on an upcoming project, though our requirement is to log all these actions to our ELK stack. I was wondering how hard it could be to create a new driver for thephpleague/flysystem that would use Elasticsearch as a disk in L5 filestystem? Probably not that hard… I don’t know.

  • great job, was just planning this month how to manage this in our app.

  • Bell

    Does last() filter the results from all()? Is one record retrieved from the database or is *all* records retrieved and then filtered by last()?

    • deductionmaster

      Yes if translated to native mysql syntax it will look like this SELECT fields FROM table ORDER BY id DESC LIMIT 1;

      • Bell

        It’s a huge difference between using a LIMIT clause and fetching all rows from database → PHP.

        • deductionmaster

          Yes, the speed brah

  • Bruno Seixas

    Great package, really comes in handy for (I would say) most of all projects =)

  • Pingback: Freek Van der Herten: A package to log activity in a Laravel app – SourceCode()

  • This has to be the best timing ever. I was just about to implement a similar strategy for activity logging for a activity/history feed with using just Laravel’s model events and scheduled cleanup. This will make it a lot easier, thank you!

  • Interuptic

    Too bad this new package, and all the other new ones you guys are making, are marked as PHP 7 only. My company will not upgrade their hosting soon. Gotta stick back to spatie/laravel-activitylog

  • Pingback: Laravel News Collection – A Coder's Life()

  • Pingback: PHP-Дайджест № 88 – интересные новости, материалы и инструменты (13 июня – 17 июля 2016) - itfm.pro()

  • Pingback: Laravel News Collection – A Coder's Life()

  • Mitja Železnikar

    Is possible to set causerid not by default guard. I have api and web users and would need something like
    $auth->guard($guard)->user(); where guard would be passed to consturctor.

    Is this possible?

  • i’m thinking about changing the datatype of the properties column to jsonb and add indexes in postgres to speed up querying the activitylog a bit. do you have any experience with this – will it work properly?