Laravel-activitylog: Allow to log system activity without a causer or a null causer

Created on 19 Jul 2019  路  8Comments  路  Source: spatie/laravel-activitylog

It's not clear from the documentation if this can be done or not.

Sometimes there can be activity triggered on events without a causer. Examples are when an action is taken by an unregistered user, a SYSTEM Cron, or a Bot.

Example log items can be:
'Project 123 was archived by the SYSTEM due to non-activity'
'GithubBot locked this thread on 23/05/2019'
'Anonymous user viewed the phone number'
etc

I think the workaround would be to create users with the names 'SYSTEM', 'Bot' etc, and hardcode that userID. Which can cause problems in production and testing environments.

Is there a better way to log such activities?

enhancement hacktoberfest help wanted

All 8 comments

Hey,

the causer columns are already nullable if this line returns null https://github.com/spatie/laravel-activitylog/blob/d5fd05eb9edcb2416ada4f1e026d47ee9f8706a3/src/ActivityLogger.php#L196 you won't have a causer.

If you want to log a system activity with a logged in user this could be done by creating the Activity model directly or override the logger service and change some methods.

as explained by @Gummibeer.
If you would want to customize "causedBy" logic then you will need to do following steps to accomplish that:

  1. Create a new ActivityLogger class which will extend "SpatieActivitylogActivityLogger" and override the "getActivity" method:

    use SpatieActivitylogActivitylogServiceProvider;
    use SpatieActivitylogActivityLogger as SpatieActivityLogger;
    use SpatieActivitylog\ContractsActivity as ActivityContract;

    class ActivityLogger extends SpatieActivityLogger
    {
    private $causedBy;

         protected function getActivity(): ActivityContract
         {
             $this->causedBy = $this->auth->guard($this->authDriver)->user();
    
             // Your logic if the causer is null
             if(empty($this->causedBy)){
                  // do something when causer is null.
              }
    
             if (! $this->activity instanceof ActivityContract) {
                 $this->activity = ActivitylogServiceProvider::getActivityModelInstance();
                $this
                   ->useLog($this->defaultLogName)
                   ->withProperties([])
                   ->causedBy($this->causedBy);
            }
    
            return $this->activity;
           }
    

    }

  2. Create a new ActivitylogServiceProvider which will extend "SpatieActivitylogActivitylogServiceProvider" and register it in "config/app.php".

    Add following code in register method of newly created service provider:



    use AppActivityLogger;
    use \SpatieActivitylogActivitylogServiceProvider as SpatieActivitylogServiceProvider;

    class ActivitylogServiceProvider extends SpatieActivitylogServiceProvider
    {

       public function register()
       {
           $this->app->alias (ActivityLogger::class, \Spatie\Activitylog\ActivityLogger::class );
       }
    

    }

This is tested so you should get no issue.

@junaid-A-khan instead of the __construct() I would adjust the getActivity() method https://github.com/spatie/laravel-activitylog/blob/d5fd05eb9edcb2416ada4f1e026d47ee9f8706a3/src/ActivityLogger.php#L189-L200

This does set the init causer - so if you remove this line or adjust the condition when the causer is set yo have a null causer. The construct doesn't have to be executed for every activity log because it's a binded service which you could cache in a variable.

@Gummibeer yes, parent construct call can be removed and I'm sorry, my bad, as I tested it on an old Laravel 5.7 witch has v2.8.
I am going to update previous answer.
Thanks

Because atm it's impossible to set the causer to null and by default it's loaded from the current auth. Is an anonymous() method wanted which forces the activity to have no causer?

activity()
    ->anonymous()
    ->log('my log message');

Doing this for a whole runtime could belong to:

  • #503
  • #521
  • #560

Perhaps we can use,

activity()
    ->causedByAnonymous()
    ->log('my log message');

or

activity()
    ->causedBy('SYSTEM')
    ->log('my log message');

or

activity()
    ->causedBy(ActivityCauserInterface)
    ->log('my log message');

I had a look today at a possible solution introducing an AnonymousCauser model which should function as a "null object". Therefore, I would propose the following PR: #604 , though I have some doubt if this approach is suitable.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

farshadff picture farshadff  路  4Comments

federico-arona picture federico-arona  路  5Comments

ianrussel picture ianrussel  路  5Comments

ekandreas picture ekandreas  路  3Comments

DjKhireddine picture DjKhireddine  路  5Comments