From dd43efe1cfc5d945dd0cf29cc1199b165478832a Mon Sep 17 00:00:00 2001 From: lkearn Date: Mon, 5 Jun 2023 20:20:11 +1000 Subject: [PATCH] ENH: Use the PsrLogMessageProcessor so that custom factory created loggers can use context. --- README.md | 3 + code/AuditFactory.php | 3 +- code/AuditHook.php | 273 +++++++++++++++++++------------ code/AuditHookMFA.php | 75 +++++---- code/AuditHookManyManyList.php | 21 ++- code/AuditHookMemberGroupSet.php | 21 ++- code/AuditHookSessionManager.php | 21 ++- code/AuditedEventType.php | 12 ++ 8 files changed, 260 insertions(+), 169 deletions(-) create mode 100644 code/AuditedEventType.php diff --git a/README.md b/README.md index 74a328b..4167b7a 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ public function dostuff() $this->auditLogger->info('stuff happened'); // You can also pass an arbitrary context array which will be included in the log. $this->auditLogger->warn('stuff happened', ['defcon' => 'amber']); + // By default we use the PsrLogMessageProcessor so you can created contextualised messages using the {key} syntax. + $this->auditLogger->info('stuff happened {defcon}', ['defcon' => 'amber']); } ``` @@ -49,6 +51,7 @@ Here is what will appear in the audit log on your dev machine (the exact format ``` Aug 24 11:09:02 SilverStripe_audit[80615]: stuff happened [] {"real_ip":"127.0.0.1","url":"/do-stuff/","http_method":"GET","server":"localhost","referrer":null} Aug 24 11:09:02 SilverStripe_audit[80615]: stuff happened {"defcon":"amber"} {"real_ip":"127.0.0.1","url":"/do-stuff/","http_method":"GET","server":"localhost","referrer":null} +Aug 24 11:09:02 SilverStripe_audit[80615]: stuff happened amber {"defcon":"amber"} {"real_ip":"127.0.0.1","url":"/do-stuff/","http_method":"GET","server":"localhost","referrer":null} ``` ## Troubleshooting diff --git a/code/AuditFactory.php b/code/AuditFactory.php index ebd4015..834f1ec 100644 --- a/code/AuditFactory.php +++ b/code/AuditFactory.php @@ -6,6 +6,7 @@ use Monolog\Formatter\LineFormatter; use Monolog\Handler\SyslogHandler; use Monolog\Logger; +use Monolog\Processor\PsrLogMessageProcessor; use Monolog\Processor\WebProcessor; use SilverStripe\Core\Injector\Factory; @@ -21,7 +22,6 @@ public function create($service, array $params = []) throw new Exception('AuditFactory does not support passing params.'); } - $obj = null; switch ($service) { case 'AuditLogger': $log = new Logger('audit'); @@ -34,6 +34,7 @@ public function create($service, array $params = []) ])); $syslog->pushProcessor(new RealIPProcessor()); + $syslog->pushProcessor(new PsrLogMessageProcessor()); $formatter = new LineFormatter("%level_name%: %message% %context% %extra%"); $syslog->setFormatter($formatter); $log->pushHandler($syslog); diff --git a/code/AuditHook.php b/code/AuditHook.php index a791fbe..3bf29b1 100644 --- a/code/AuditHook.php +++ b/code/AuditHook.php @@ -2,6 +2,7 @@ namespace SilverStripe\Auditor; +use Psr\Log\LoggerInterface; use SilverStripe\Control\Email\Email; use SilverStripe\Core\Injector\Injector; use SilverStripe\ORM\DataExtension; @@ -19,6 +20,9 @@ */ class AuditHook extends DataExtension { + /** + * @return LoggerInterface + */ protected function getAuditLogger() { // We cannot use the 'dependencies' private property, because this will prevent us @@ -31,6 +35,7 @@ protected function getAuditLogger() public static function handle_manipulation($manipulation) { + /** @var LoggerInterface $auditLogger */ $auditLogger = Injector::inst()->get('AuditLogger'); $currentMember = Security::getCurrentUser(); @@ -61,6 +66,7 @@ public static function handle_manipulation($manipulation) ) { $className = $schema->tableClass($table); + /** @var DataObject $data */ $data = $className::get()->byID($details['id']); if (!$data) { continue; @@ -69,12 +75,14 @@ public static function handle_manipulation($manipulation) $extendedText = ''; if ($table === $schema->tableName(Group::class)) { + /** @var Group $data */ $extendedText = sprintf( 'Effective permissions: %s', implode(', ', $data->Permissions()->column('Code')) ); } if ($table === $schema->tableName(PermissionRole::class)) { + /** @var PermissionRole $data */ $extendedText = sprintf( 'Effective groups: %s, Effective permissions: %s', implode(', ', $data->Groups()->column('Title')), @@ -82,28 +90,40 @@ public static function handle_manipulation($manipulation) ); } if ($table === $schema->tableName(PermissionRoleCode::class)) { + /** @var PermissionRoleCode $data */ $extendedText = sprintf( 'Effective code: %s', $data->Code ); } if ($table === $schema->tableName(Member::class)) { + /** @var Member $data */ $extendedText = sprintf( 'Effective groups: %s', implode(', ', $data->Groups()->column('Title')) ); } - $auditLogger->info(sprintf( - '"%s" (ID: %s) %s (ID: %s, ClassName: %s, Title: "%s", %s)', - $currentMember->Email ?: $currentMember->Title, - $currentMember->ID, - $actionText, - $details['id'], - $data->ClassName, - $data->Title, - $extendedText - )); + $crud = AuditedEventType::CREATE; + if ($details['command'] === 'update') { + $crud = AuditedEventType::UPDATE; + } elseif ($details['command'] === 'insert') { + $crud = AuditedEventType::CREATE; + } + + $auditLogger->info( + '"{actor_email_or_title}" (ID: actor_id) {action} (ID: {object_id}, ClassName: {object_class}, Title: "{object_title}", {extended_text})', + [ + 'actor_email_or_title' => $currentMember->Email ?: $currentMember->Title, + 'actor_id' => $currentMember->ID, + 'action' => $actionText, + 'object_id' => $details['id'], + 'object_class' => $data->getClassName(), + 'object_title' => $data->Title, + 'extended_text' => $extendedText, + 'type' => $crud, + ] + ); } // log PermissionRole being added to a Group @@ -117,15 +137,18 @@ public static function handle_manipulation($manipulation) $details['fields']['GroupID'], $details['fields']['PermissionRoleID'] ))->value()) { - $auditLogger->info(sprintf( - '"%s" (ID: %s) added PermissionRole "%s" (ID: %s) to Group "%s" (ID: %s)', - $currentMember->Email ?: $currentMember->Title, - $currentMember->ID, - $role->Title, - $role->ID, - $group->Title, - $group->ID - )); + $auditLogger->info( + '"{actor_email_or_title}" (ID: {actor_id}) added PermissionRole "{permission_role_title}" (ID: {permission_role_id}) to Group "{group_title}" (ID: {group_id})', + [ + 'actor_email_or_title' => $currentMember->Email ?: $currentMember->Title, + 'actor_id' => $currentMember->ID, + 'permission_role_title' => $role->Title, + 'permission_role_id' => $role->ID, + 'group_title' => $group->Title, + 'group_id' => $group->ID, + 'type' => AuditedEventType::UPDATE, + ] + ); } } @@ -140,15 +163,18 @@ public static function handle_manipulation($manipulation) $details['fields']['GroupID'], $details['fields']['MemberID'] ))->value()) { - $auditLogger->info(sprintf( - '"%s" (ID: %s) added Member "%s" (ID: %s) to Group "%s" (ID: %s)', - $currentMember->Email ?: $currentMember->Title, - $currentMember->ID, - $member->Email ?: $member->Title, - $member->ID, - $group->Title, - $group->ID - )); + $auditLogger->info( + '"{actor_email_or_title}" (ID: {actor_id}) added Member "{member_email_or_title}" (ID: {member_id}) to Group "{group_title}" (ID: {group_id})', + [ + 'actor_email_or_title' => $currentMember->Email ?: $currentMember->Title, + 'actor_id' => $currentMember->ID, + 'member_email_or_title' => $member->Email ?: $member->Title, + 'member_id' => $member->ID, + 'group_title' => $group->Title, + 'group_id' => $group->ID, + 'type' => AuditedEventType::UPDATE, + ] + ); } } } @@ -182,19 +208,22 @@ public function onAfterPublish(&$original) $effectiveEditorGroups = $this->owner->CanEditType; } - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) published %s "%s" (ID: %s, Version: %s, ClassName: %s, Effective ViewerGroups: %s, ' - . 'Effective EditorGroups: %s)', - $member->Email ?: $member->Title, - $member->ID, - $this->owner->singular_name(), - $this->owner->Title, - $this->owner->ID, - $this->owner->Version, - $this->owner->ClassName, - $effectiveViewerGroups, - $effectiveEditorGroups - )); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) published {object_singular_name} "{object_title}" (ID: {object_id}, Version: {object_version}, ClassName: {object_class}, Effective ViewerGroups: {effective_viewer_groups}, ' + . 'Effective EditorGroups: {effective_editor_groups})', + [ + 'actor_email_or_title' => $member->Email ?: $member->Title, + 'actor_id' => $member->ID, + 'object_singular_name' => $this->owner->singular_name(), + 'object_title' => $this->owner->Title, + 'object_id' => $this->owner->ID, + 'object_version' => $this->owner->Version, + 'object_class' => $this->owner->getClassName(), + 'effective_viewer_groups' => $effectiveViewerGroups, + 'effective_editor_groups' => $effectiveEditorGroups, + 'type' => AuditedEventType::CREATE, + ], + ); } /** @@ -207,14 +236,17 @@ public function onAfterUnpublish() return false; } - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) unpublished %s "%s" (ID: %s)', - $member->Email ?: $member->Title, - $member->ID, - $this->owner->singular_name(), - $this->owner->Title, - $this->owner->ID - )); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) unpublished {object_singular_name} "{object_title}" (ID: {object_id})', + [ + 'actor_email_or_title' => $member->Email ?: $member->Title, + 'actor_id' => $member->ID, + 'object_singular_name' => $this->owner->singular_name(), + 'object_title' => $this->owner->Title, + 'object_id' => $this->owner->ID, + 'type' => AuditedEventType::DELETE + ] + ); } /** @@ -227,15 +259,18 @@ public function onAfterRevertToLive() return false; } - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) reverted %s "%s" (ID: %s) to it\'s live version (#%d)', - $member->Email ?: $member->Title, - $member->ID, - $this->owner->singular_name(), - $this->owner->Title, - $this->owner->ID, - $this->owner->Version - )); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) reverted {object_singular_name} "{object_title}" (ID: {object_id}) to it\'s live version (#{object_version})', + [ + 'actor_email_or_title' => $member->Email ?: $member->Title, + 'actor_id' => $member->ID, + 'object_singular_name' => $this->owner->singular_name(), + 'object_title' => $this->owner->Title, + 'object_id' => $this->owner->ID, + 'object_version' => $this->owner->Version, + 'type' => AuditedEventType::UPDATE, + ], + ); } /** @@ -248,14 +283,17 @@ public function onAfterDuplicate() return false; } - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) duplicated %s "%s" (ID: %s)', - $member->Email ?: $member->Title, - $member->ID, - $this->owner->singular_name(), - $this->owner->Title, - $this->owner->ID - )); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) duplicated {object_singular_name} "{object_title}" (ID: {object_id})', + [ + 'actor_email_or_title' => $member->Email ?: $member->Title, + 'actor_id' => $member->ID, + 'object_singular_name' => $this->owner->singular_name(), + 'object_title' => $this->owner->Title, + 'object_id' => $this->owner->ID, + 'type' => AuditedEventType::CREATE + ] + ); } /** @@ -268,14 +306,17 @@ public function onAfterDelete() return false; } - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) deleted %s "%s" (ID: %s)', - $member->Email ?: $member->Title, - $member->ID, - $this->owner->singular_name(), - $this->owner->Title, - $this->owner->ID - )); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) deleted {object_singular_name} "{object_title}" (ID: {object_id})', + [ + 'actor_email_or_title' => $member->Email ?: $member->Title, + 'actor_id' => $member->ID, + 'object_singular_name' => $this->owner->singular_name(), + 'object_title' => $this->owner->Title, + 'object_id' => $this->owner->ID, + 'type' => AuditedEventType::DELETE, + ], + ); } /** @@ -288,14 +329,17 @@ public function onAfterRestoreToStage() return false; } - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) restored %s "%s" to stage (ID: %s)', - $member->Email ?: $member->Title, - $member->ID, - $this->owner->singular_name(), - $this->owner->Title, - $this->owner->ID - )); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) restored {object_singular_name} "{object_title}" to stage (ID: {object_id})', + [ + 'actor_email_or_title' => $member->Email ?: $member->Title, + 'actor_id' => $member->ID, + 'object_singular_name' => $this->owner->singular_name(), + 'object_title' => $this->owner->Title, + 'object_id' => $this->owner->ID, + 'type' => AuditedEventType::CREATE, + ], + ); } /** @@ -303,11 +347,14 @@ public function onAfterRestoreToStage() */ public function afterMemberLoggedIn() { - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) successfully logged in', - $this->owner->Email ?: $this->owner->Title, - $this->owner->ID - )); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) successfully logged in', + [ + 'actor_email_or_title' => $this->owner->Email ?: $this->owner->Title, + 'actor_id' => $this->owner->ID, + 'type' => AuditedEventType::NOTICE, + ] + ); } /** @@ -315,11 +362,14 @@ public function afterMemberLoggedIn() */ public function memberAutoLoggedIn() { - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) successfully restored autologin session', - $this->owner->Email ?: $this->owner->Title, - $this->owner->ID - )); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) successfully restored autologin session', + [ + 'actor_email_or_title' => $this->owner->Email ?: $this->owner->Title, + 'actor_id' => $this->owner->ID, + 'type' => AuditedEventType::NOTICE, + ] + ); } /** @@ -334,12 +384,15 @@ public function authenticationFailed($data) if (empty($login)) { return $this->getAuditLogger()->warning( - 'Could not determine username/email of failed authentication. '. - 'This could be due to login form not using Email or Login field for POST data.' + 'Could not determine username/email of failed authentication. ' . + 'This could be due to login form not using Email or Login field for POST data.' ); } - $this->getAuditLogger()->info(sprintf('Failed login attempt using email "%s"', $login)); + $this->getAuditLogger()->info('Failed login attempt using email "{email}"', [ + 'email' => $login, + 'type' => AuditedEventType::NOTICE, + ]); } /** @@ -365,13 +418,16 @@ public function onAfterInit() protected function logPermissionDenied($statusCode, $member) { - $this->getAuditLogger()->info(sprintf( - 'HTTP code %s - "%s" (ID: %s) is denied access to %s', - $statusCode, - $member->Email ?: $member->Title, - $member->ID, - $_SERVER['REQUEST_URI'] - )); + $this->getAuditLogger()->info( + 'HTTP code {status_code} - "{actor_email_or_title}" (ID: {actor_id}) is denied access to {request_uri}', + [ + 'status_code' => $statusCode, + 'actor_email_or_title' => $member->Email ?: $member->Title, + 'actor_id' => $member->ID, + 'request_uri' => $_SERVER['REQUEST_URI'], + 'type' => AuditedEventType::NOTICE, + ] + ); } /** @@ -379,10 +435,13 @@ protected function logPermissionDenied($statusCode, $member) */ public function afterMemberLoggedOut() { - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) successfully logged out', - $this->owner->Email ?: $this->owner->Title, - $this->owner->ID - )); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) successfully logged out', + [ + $this->owner->Email ?: $this->owner->Title, + $this->owner->ID, + 'type' => AuditedEventType::NOTICE, + ] + ); } } diff --git a/code/AuditHookMFA.php b/code/AuditHookMFA.php index 96ac242..193acc7 100644 --- a/code/AuditHookMFA.php +++ b/code/AuditHookMFA.php @@ -22,12 +22,13 @@ class AuditHookMFA extends DataExtension public function onMethodVerificationSuccess(Member $member, $method) { $this->getAuditLogger()->info( - sprintf( - '"%s" (ID: %s) successfully verified using MFA method', - $member->Email ?: $member->Title, - $member->ID - ), - ['method' => get_class($method)] + '"{actor_email_or_title}" (ID: {actor_id}) successfully verified using MFA method', + [ + 'actor_email_or_title' => $member->Email ?: $member->Title, + 'actor_id' => $member->ID, + 'method' => get_class($method), + 'type' => AuditedEventType::NOTICE, + ] ); } @@ -40,19 +41,22 @@ public function onMethodVerificationSuccess(Member $member, $method) public function onMethodVerificationFailure(Member $member, $method) { $context = [ + 'actor_email_or_title' => $member->Email ?: $member->Title, + 'actor_id' => $member->ID, 'method' => get_class($method), + 'type' => AuditedEventType::NOTICE, ]; + if ($lockOutAfterCount = $member->config()->get('lock_out_after_incorrect_logins')) { // Add information about how many attempts have been made $context['attempts'] = $member->FailedLoginCount; $context['attempt_limit'] = $lockOutAfterCount; } - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) failed to verify using MFA method', - $member->Email ?: $member->Title, - $member->ID - ), $context); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) failed to verify using MFA method', + $context, + ); } /** @@ -62,11 +66,14 @@ public function onMethodVerificationFailure(Member $member, $method) */ public function onSkipRegistration(Member $member) { - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) skipped MFA registration', - $member->Email ?: $member->Title, - $member->ID - )); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) skipped MFA registration', + [ + 'actor_email_or_title' => $member->Email ?: $member->Title, + 'actor_id' => $member->ID, + 'type' => AuditedEventType::NOTICE, + ] + ); } /** @@ -75,15 +82,15 @@ public function onSkipRegistration(Member $member) */ public function onRegisterMethod(Member $member, $method) { - $context = [ - 'method' => get_class($method), - ]; - - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) registered MFA method', - $member->Email ?: $member->Title, - $member->ID - ), $context); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) registered MFA method', + [ + 'actor_email_or_title' => $member->Email ?: $member->Title, + 'actor_id' => $member->ID, + 'method' => get_class($method), + 'type' => AuditedEventType::CREATE, + ] + ); } /** @@ -94,15 +101,15 @@ public function onRegisterMethod(Member $member, $method) */ public function onRegisterMethodFailure(Member $member, $method) { - $context = [ - 'method' => get_class($method), - ]; - - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) failed registering new MFA method', - $member->Email ?: $member->Title, - $member->ID - ), $context); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) failed registering new MFA method', + [ + 'actor_email_or_title' => $member->Email ?: $member->Title, + 'actor_id' => $member->ID, + 'method' => get_class($method), + 'type' => AuditedEventType::NOTICE, + ] + ); } /** diff --git a/code/AuditHookManyManyList.php b/code/AuditHookManyManyList.php index 513079a..fe8b35a 100644 --- a/code/AuditHookManyManyList.php +++ b/code/AuditHookManyManyList.php @@ -34,15 +34,18 @@ public function removeByID($itemID) return; } - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) removed Member "%s" (ID: %s) from Group "%s" (ID: %s)', - $currentMember->Email ?: $currentMember->Title, - $currentMember->ID, - $member->Email ?: $member->Title, - $member->ID, - $group->Title, - $group->ID - )); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) removed Member "{member_email_or_title}" (ID: {member_id}) from Group "{group_title}" (ID: {group_id})', + [ + 'actor_email_or_title' => $currentMember->Email ?: $currentMember->Title, + 'actor_id' => $currentMember->ID, + 'member_email_or_title' => $member->Email ?: $member->Title, + 'member_id' => $member->ID, + 'group_title' => $group->Title, + 'group_id' => $group->ID, + 'type' => AuditedEventType::UPDATE + ], + ); } } diff --git a/code/AuditHookMemberGroupSet.php b/code/AuditHookMemberGroupSet.php index 197fb13..94a04fd 100644 --- a/code/AuditHookMemberGroupSet.php +++ b/code/AuditHookMemberGroupSet.php @@ -34,15 +34,18 @@ public function removeByID($itemID) return; } - $this->getAuditLogger()->info(sprintf( - '"%s" (ID: %s) removed Member "%s" (ID: %s) from Group "%s" (ID: %s)', - $currentMember->Email ?: $currentMember->Title, - $currentMember->ID, - $member->Email ?: $member->Title, - $member->ID, - $group->Title, - $group->ID - )); + $this->getAuditLogger()->info( + '"{actor_email_or_title}" (ID: {actor_id}) removed Member "{member_email_or_title}" (ID: {member_id}) from Group "{group_title}" (ID: {group_id})', + [ + 'actor_email_or_title' => $currentMember->Email ?: $currentMember->Title, + 'actor_id' => $currentMember->ID, + 'member_email_or_title' => $member->Email ?: $member->Title, + 'member_id' => $member->ID, + 'group_title' => $group->Title, + 'group_id' => $group->ID, + 'type' => AuditedEventType::UPDATE, + ] + ); } } diff --git a/code/AuditHookSessionManager.php b/code/AuditHookSessionManager.php index 4029c5e..b0bc596 100644 --- a/code/AuditHookSessionManager.php +++ b/code/AuditHookSessionManager.php @@ -6,7 +6,7 @@ use SilverStripe\Core\Injector\Injector; use SilverStripe\ORM\DataExtension; use SilverStripe\Security\Security; -use SilverStripe\SessionManager\Model\LoginSession; +use SilverStripe\SessionManager\Models\LoginSession; /** * Provides logging actions on extension hooks from certain silverstripe/session-manager actions. @@ -25,14 +25,17 @@ public function onBeforeRemoveLoginSession(LoginSession $loginSession) if (is_null($member) || $member->ID === 0 || is_null($currentUser) || $currentUser->ID === 0) { return; } - $this->getAuditLogger()->info(sprintf( - 'Login session (ID: %s) for Member "%s" (ID: %s) is being removed by Member "%s" (ID: %s)', - $loginSession->ID, - $member->Email ?: $member->Title, - $member->ID, - $currentUser->Email ?: $currentUser->Title, - $currentUser->ID - )); + $this->getAuditLogger()->info( + 'Login session (ID: {login_session_id}) for Member "{member_email_or_title}" (ID: {member_id}) is being removed by Member "{actor_email_or_title}" (ID: {actor_id})', + [ + 'login_session_id' => $loginSession->ID, + 'member_email_or_title' => $member->Email ?: $member->Title, + 'member_id' => $member->ID, + 'actor_email_or_title' => $currentUser->Email ?: $currentUser->Title, + 'actor_id' => $currentUser->ID, + 'crud' => AuditedEventType::DELETE, + ] + ); } /** diff --git a/code/AuditedEventType.php b/code/AuditedEventType.php new file mode 100644 index 0000000..396fcaf --- /dev/null +++ b/code/AuditedEventType.php @@ -0,0 +1,12 @@ +