From dc9101d5ff8720d8eb92f1545f1630106061058e Mon Sep 17 00:00:00 2001 From: William Allen Date: Wed, 13 May 2026 18:17:16 -0400 Subject: [PATCH] Add logging to all GraphQL mutations All mutations are currently untraceable, making debugging difficult. This PR adds basic logging to each of our existing mutations to resolve this. --- app/GraphQL/Mutations/ChangeGlobalRole.php | 3 +++ app/GraphQL/Mutations/ChangeProjectRole.php | 3 +++ app/GraphQL/Mutations/ClaimSite.php | 3 +++ app/GraphQL/Mutations/CreateAuthenticationToken.php | 8 ++++++++ app/GraphQL/Mutations/CreateComment.php | 3 +++ app/GraphQL/Mutations/CreateGlobalInvitation.php | 3 +++ app/GraphQL/Mutations/CreatePinnedTestMeasurement.php | 4 ++++ app/GraphQL/Mutations/CreateProject.php | 4 ++++ app/GraphQL/Mutations/CreateRepository.php | 4 ++++ app/GraphQL/Mutations/DeleteAuthenticationToken.php | 3 +++ app/GraphQL/Mutations/DeletePinnedTestMeasurement.php | 4 ++++ app/GraphQL/Mutations/DeleteRepository.php | 4 ++++ app/GraphQL/Mutations/InviteToProject.php | 3 +++ app/GraphQL/Mutations/JoinProject.php | 3 +++ app/GraphQL/Mutations/RemoveProjectUser.php | 3 +++ app/GraphQL/Mutations/RemoveUser.php | 4 ++++ app/GraphQL/Mutations/RevokeGlobalInvitation.php | 4 ++++ app/GraphQL/Mutations/RevokeProjectInvitation.php | 4 ++++ app/GraphQL/Mutations/UnclaimSite.php | 3 +++ .../Mutations/UpdatePinnedTestMeasurementOrder.php | 4 ++++ app/GraphQL/Mutations/UpdateProject.php | 4 ++++ app/GraphQL/Mutations/UpdateSiteDescription.php | 3 +++ 22 files changed, 81 insertions(+) diff --git a/app/GraphQL/Mutations/ChangeGlobalRole.php b/app/GraphQL/Mutations/ChangeGlobalRole.php index 4ef6ad544a..f7f516bd5f 100644 --- a/app/GraphQL/Mutations/ChangeGlobalRole.php +++ b/app/GraphQL/Mutations/ChangeGlobalRole.php @@ -7,6 +7,7 @@ use App\Enums\GlobalRole; use App\Exceptions\GraphQLMutationException; use App\Models\User; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Rule; use Illuminate\Validation\ValidationException; @@ -55,6 +56,8 @@ public function __invoke(null $_, array $args): self $userToChange->admin = $args['role'] === GlobalRole::ADMINISTRATOR; $userToChange->save(); + Log::info("User {$user->id} changed global role to {$args['role']->value} for user {$userToChange->id}."); + $this->user = $userToChange; return $this; diff --git a/app/GraphQL/Mutations/ChangeProjectRole.php b/app/GraphQL/Mutations/ChangeProjectRole.php index 3a980ea029..c032958a5d 100644 --- a/app/GraphQL/Mutations/ChangeProjectRole.php +++ b/app/GraphQL/Mutations/ChangeProjectRole.php @@ -9,6 +9,7 @@ use App\Models\Project; use App\Models\User; use Exception; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Rule; @@ -65,6 +66,8 @@ public function __invoke(null $_, array $args): self }, ]); + Log::info("User {$user->id} changed role to {$args['role']->value} for user {$userToChange->id} in project {$project->id}."); + if ($rowsEdited !== 1) { throw new Exception('Failed to update pivot table with new role.'); } diff --git a/app/GraphQL/Mutations/ClaimSite.php b/app/GraphQL/Mutations/ClaimSite.php index 221a815579..5e2f58f363 100644 --- a/app/GraphQL/Mutations/ClaimSite.php +++ b/app/GraphQL/Mutations/ClaimSite.php @@ -7,6 +7,7 @@ use App\Exceptions\GraphQLMutationException; use App\Models\Site; use App\Models\User; +use Illuminate\Support\Facades\Log; final class ClaimSite extends AbstractMutation { @@ -36,6 +37,8 @@ public function __invoke(null $_, array $args): self $site->maintainers()->syncWithoutDetaching($user); + Log::info("User {$user->id} claimed site {$site->id}."); + $this->site = $site; $this->user = $user; diff --git a/app/GraphQL/Mutations/CreateAuthenticationToken.php b/app/GraphQL/Mutations/CreateAuthenticationToken.php index d138a93dba..3e7a47c6ab 100644 --- a/app/GraphQL/Mutations/CreateAuthenticationToken.php +++ b/app/GraphQL/Mutations/CreateAuthenticationToken.php @@ -10,6 +10,7 @@ use Illuminate\Auth\AuthenticationException; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Log; final class CreateAuthenticationToken extends AbstractMutation { @@ -47,6 +48,13 @@ public function __invoke(null $_, array $args): self $args['expiration'], ); + $logMessage = "User {$user->id} created authentication token with scope {$this->token->scope}"; + if ($this->token->projectid > 0) { + $logMessage .= " for project {$this->token->projectid}"; + } + + Log::info("$logMessage."); + return $this; } } diff --git a/app/GraphQL/Mutations/CreateComment.php b/app/GraphQL/Mutations/CreateComment.php index 693ae2d211..58c9aa0637 100644 --- a/app/GraphQL/Mutations/CreateComment.php +++ b/app/GraphQL/Mutations/CreateComment.php @@ -8,6 +8,7 @@ use App\Models\Comment; use Illuminate\Auth\AuthenticationException; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Log; final class CreateComment extends AbstractMutation { @@ -41,6 +42,8 @@ public function __invoke(null $_, array $args): self $this->comment = $comment->refresh(); + Log::info("User {$user->id} left comment {$comment->id} on build {$build?->id}."); + return $this; } } diff --git a/app/GraphQL/Mutations/CreateGlobalInvitation.php b/app/GraphQL/Mutations/CreateGlobalInvitation.php index fd0881bd55..8a733e08bc 100644 --- a/app/GraphQL/Mutations/CreateGlobalInvitation.php +++ b/app/GraphQL/Mutations/CreateGlobalInvitation.php @@ -12,6 +12,7 @@ use Exception; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; @@ -74,6 +75,8 @@ public function __invoke(null $_, array $args): self 'password' => Hash::make($password), ]); + Log::info("User {$user->id} invited user {$this->invitedUser->email} with role {$this->invitedUser->role->value}."); + // The email gets sent to the queue, so we have no way to know immediately whether it was sent or not. // TODO: We should eventually track whether the email was actually sent. Mail::to($args['email'])->send(new InvitedToCdash($this->invitedUser, $password)); diff --git a/app/GraphQL/Mutations/CreatePinnedTestMeasurement.php b/app/GraphQL/Mutations/CreatePinnedTestMeasurement.php index 166ba5c797..fbf8efae10 100644 --- a/app/GraphQL/Mutations/CreatePinnedTestMeasurement.php +++ b/app/GraphQL/Mutations/CreatePinnedTestMeasurement.php @@ -7,6 +7,7 @@ use App\Models\PinnedTestMeasurement; use App\Models\Project; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Log; final class CreatePinnedTestMeasurement extends AbstractMutation { @@ -35,6 +36,9 @@ public function __invoke(null $_, array $args): self 'position' => $nextAvailablePosition, ]); + $user = auth()->user(); + Log::info("User {$user?->id} created pinned test measurement {$this->pinnedTestMeasurement?->id} for project {$project?->id}."); + return $this; } } diff --git a/app/GraphQL/Mutations/CreateProject.php b/app/GraphQL/Mutations/CreateProject.php index 4a05e97dba..5968d7ecbb 100644 --- a/app/GraphQL/Mutations/CreateProject.php +++ b/app/GraphQL/Mutations/CreateProject.php @@ -7,6 +7,7 @@ use App\Models\Project; use App\Services\ProjectService; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Log; class CreateProject { @@ -27,6 +28,9 @@ public function __invoke(null $_, array $args): Project 'role' => Project::PROJECT_ADMIN, ]); + $user = auth()->user(); + Log::info("User {$user?->id} created project {$project->id}."); + return $project; } } diff --git a/app/GraphQL/Mutations/CreateRepository.php b/app/GraphQL/Mutations/CreateRepository.php index 571b7c1958..58fb8c1b3b 100644 --- a/app/GraphQL/Mutations/CreateRepository.php +++ b/app/GraphQL/Mutations/CreateRepository.php @@ -7,6 +7,7 @@ use App\Models\Project; use App\Models\Repository; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Log; final class CreateRepository extends AbstractMutation { @@ -34,6 +35,9 @@ public function __invoke(null $_, array $args): self 'branch' => $args['branch'], ]); + $user = auth()->user(); + Log::info("User {$user?->id} created repository {$this->repository?->id} for project {$project?->id}."); + return $this; } } diff --git a/app/GraphQL/Mutations/DeleteAuthenticationToken.php b/app/GraphQL/Mutations/DeleteAuthenticationToken.php index e953bc33f6..cf5010984c 100644 --- a/app/GraphQL/Mutations/DeleteAuthenticationToken.php +++ b/app/GraphQL/Mutations/DeleteAuthenticationToken.php @@ -7,6 +7,7 @@ use App\Models\AuthToken; use App\Utils\AuthTokenUtil; use Illuminate\Auth\AuthenticationException; +use Illuminate\Support\Facades\Log; final class DeleteAuthenticationToken extends AbstractMutation { @@ -26,6 +27,8 @@ public function __invoke(null $_, array $args): self throw new AuthenticationException('This action is unauthorized.'); } + Log::info("User {$userid} deleted authentication token {$args['tokenId']}."); + return $this; } } diff --git a/app/GraphQL/Mutations/DeletePinnedTestMeasurement.php b/app/GraphQL/Mutations/DeletePinnedTestMeasurement.php index 142253cb3a..42fae6b6fe 100644 --- a/app/GraphQL/Mutations/DeletePinnedTestMeasurement.php +++ b/app/GraphQL/Mutations/DeletePinnedTestMeasurement.php @@ -6,6 +6,7 @@ use App\Models\PinnedTestMeasurement; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Log; final class DeletePinnedTestMeasurement extends AbstractMutation { @@ -22,6 +23,9 @@ public function __invoke(null $_, array $args): self $measurement?->delete(); + $user = auth()->user(); + Log::info("User {$user?->id} deleted pinned test measurement {$args['id']}."); + return $this; } } diff --git a/app/GraphQL/Mutations/DeleteRepository.php b/app/GraphQL/Mutations/DeleteRepository.php index b653d535f9..eef2e30344 100644 --- a/app/GraphQL/Mutations/DeleteRepository.php +++ b/app/GraphQL/Mutations/DeleteRepository.php @@ -6,6 +6,7 @@ use App\Models\Repository; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Log; final class DeleteRepository extends AbstractMutation { @@ -22,6 +23,9 @@ public function __invoke(null $_, array $args): self $repository?->delete(); + $user = auth()->user(); + Log::info("User {$user?->id} deleted repository {$args['repositoryId']}."); + return $this; } } diff --git a/app/GraphQL/Mutations/InviteToProject.php b/app/GraphQL/Mutations/InviteToProject.php index 349dac26be..4b668b2f75 100644 --- a/app/GraphQL/Mutations/InviteToProject.php +++ b/app/GraphQL/Mutations/InviteToProject.php @@ -12,6 +12,7 @@ use App\Models\User; use Exception; use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Rule; @@ -77,6 +78,8 @@ public function __invoke(null $_, array $args): self 'invitation_timestamp' => Carbon::now(), ]); + Log::info("User {$user->id} invited user {$args['email']} to project {$project->id} with role {$args['role']->value}."); + // The email gets sent to the queue, so we have no way to know immediately whether it was sent or not. // TODO: We should eventually track whether the email was actually sent. Mail::to($args['email'])->send(new InvitedToProject($this->invitedUser)); diff --git a/app/GraphQL/Mutations/JoinProject.php b/app/GraphQL/Mutations/JoinProject.php index b87f7588aa..2cc11c4cf0 100644 --- a/app/GraphQL/Mutations/JoinProject.php +++ b/app/GraphQL/Mutations/JoinProject.php @@ -7,6 +7,7 @@ use App\Exceptions\GraphQLMutationException; use App\Models\Project; use App\Models\User; +use Illuminate\Support\Facades\Log; final class JoinProject extends AbstractMutation { @@ -41,6 +42,8 @@ public function __invoke(null $_, array $args): self 'role' => Project::PROJECT_USER, ]); + Log::info("User {$user->id} joined project {$project->id}."); + return $this; } } diff --git a/app/GraphQL/Mutations/RemoveProjectUser.php b/app/GraphQL/Mutations/RemoveProjectUser.php index ce7bca7797..4829ee1390 100644 --- a/app/GraphQL/Mutations/RemoveProjectUser.php +++ b/app/GraphQL/Mutations/RemoveProjectUser.php @@ -7,6 +7,7 @@ use App\Exceptions\GraphQLMutationException; use App\Models\Project; use App\Models\User; +use Illuminate\Support\Facades\Log; final class RemoveProjectUser extends AbstractMutation { @@ -44,6 +45,8 @@ public function __invoke(null $_, array $args): self $project->users()->detach($userToRemove->id); + Log::info("User {$user->id} removed user {$userToRemove->id} from project {$project->id}."); + return $this; } } diff --git a/app/GraphQL/Mutations/RemoveUser.php b/app/GraphQL/Mutations/RemoveUser.php index d2538e0b7e..506d18b904 100644 --- a/app/GraphQL/Mutations/RemoveUser.php +++ b/app/GraphQL/Mutations/RemoveUser.php @@ -7,6 +7,7 @@ use App\Exceptions\GraphQLMutationException; use App\Models\User; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Log; final class RemoveUser extends AbstractMutation { @@ -29,6 +30,9 @@ public function __invoke(null $_, array $args): self $user->delete(); + $authUser = auth()->user(); + Log::info("User {$authUser?->id} removed user {$args['userId']}."); + return $this; } } diff --git a/app/GraphQL/Mutations/RevokeGlobalInvitation.php b/app/GraphQL/Mutations/RevokeGlobalInvitation.php index f1ac754b66..3634003b76 100644 --- a/app/GraphQL/Mutations/RevokeGlobalInvitation.php +++ b/app/GraphQL/Mutations/RevokeGlobalInvitation.php @@ -7,6 +7,7 @@ use App\Exceptions\GraphQLMutationException; use App\Models\GlobalInvitation; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Log; final class RevokeGlobalInvitation extends AbstractMutation { @@ -29,6 +30,9 @@ public function __invoke(null $_, array $args): self $invitation->delete(); + $user = auth()->user(); + Log::info("User {$user?->id} revoked global invitation for {$invitation->email}."); + return $this; } } diff --git a/app/GraphQL/Mutations/RevokeProjectInvitation.php b/app/GraphQL/Mutations/RevokeProjectInvitation.php index 66a4c51c36..af0963b6ba 100644 --- a/app/GraphQL/Mutations/RevokeProjectInvitation.php +++ b/app/GraphQL/Mutations/RevokeProjectInvitation.php @@ -7,6 +7,7 @@ use App\Exceptions\GraphQLMutationException; use App\Models\ProjectInvitation; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Log; final class RevokeProjectInvitation extends AbstractMutation { @@ -29,6 +30,9 @@ public function __invoke(null $_, array $args): self $invitation->delete(); + $user = auth()->user(); + Log::info("User {$user?->id} revoked invitation for user {$invitation->email} to project {$invitation->project_id}."); + return $this; } } diff --git a/app/GraphQL/Mutations/UnclaimSite.php b/app/GraphQL/Mutations/UnclaimSite.php index f8f46933cc..79f71b1440 100644 --- a/app/GraphQL/Mutations/UnclaimSite.php +++ b/app/GraphQL/Mutations/UnclaimSite.php @@ -7,6 +7,7 @@ use App\Exceptions\GraphQLMutationException; use App\Models\Site; use App\Models\User; +use Illuminate\Support\Facades\Log; final class UnclaimSite extends AbstractMutation { @@ -36,6 +37,8 @@ public function __invoke(null $_, array $args): self $site->maintainers()->detach($user); + Log::info("User {$user->id} unclaimed site {$site->id}."); + $this->site = $site; $this->user = $user; diff --git a/app/GraphQL/Mutations/UpdatePinnedTestMeasurementOrder.php b/app/GraphQL/Mutations/UpdatePinnedTestMeasurementOrder.php index 82fc643059..570a6ea8aa 100644 --- a/app/GraphQL/Mutations/UpdatePinnedTestMeasurementOrder.php +++ b/app/GraphQL/Mutations/UpdatePinnedTestMeasurementOrder.php @@ -9,6 +9,7 @@ use App\Models\Project; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Log; final class UpdatePinnedTestMeasurementOrder extends AbstractMutation { @@ -57,6 +58,9 @@ public function __invoke(null $_, array $args): self $this->pinnedTestMeasurements = $project?->pinnedTestMeasurements()->orderBy('position')->get(); + $user = auth()->user(); + Log::info("User {$user?->id} updated pinned test measurement order for project {$project?->id}."); + return $this; } } diff --git a/app/GraphQL/Mutations/UpdateProject.php b/app/GraphQL/Mutations/UpdateProject.php index b109daed30..341bbd12a1 100644 --- a/app/GraphQL/Mutations/UpdateProject.php +++ b/app/GraphQL/Mutations/UpdateProject.php @@ -6,6 +6,7 @@ use App\Models\Project; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Log; final class UpdateProject extends AbstractMutation { @@ -26,6 +27,9 @@ public function __invoke(null $_, array $args): self $this->project = $project; + $user = auth()->user(); + Log::info("User {$user?->id} updated project {$project?->id}."); + return $this; } } diff --git a/app/GraphQL/Mutations/UpdateSiteDescription.php b/app/GraphQL/Mutations/UpdateSiteDescription.php index 80e20f1efc..ee52a2b0a4 100644 --- a/app/GraphQL/Mutations/UpdateSiteDescription.php +++ b/app/GraphQL/Mutations/UpdateSiteDescription.php @@ -7,6 +7,7 @@ use App\Exceptions\GraphQLMutationException; use App\Models\Site; use App\Models\User; +use Illuminate\Support\Facades\Log; final class UpdateSiteDescription extends AbstractMutation { @@ -41,6 +42,8 @@ public function __invoke(null $_, array $args): self $newSiteInformation['description'] = $args['description']; $site->information()->create($newSiteInformation); + Log::info("User {$user->id} updated description for site {$site->id}."); + $this->site = $site; return $this;