From 30b0d3ca08224649ac1f9771bc0474e1070da5dd Mon Sep 17 00:00:00 2001
From: Thomas Citharel <tcit@tcit.fr>
Date: Sun, 6 Nov 2022 11:57:53 +0100
Subject: [PATCH] Add GraphQL operation name, user ID and actor name in logs

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
---
 config/config.exs                             |  2 +-
 config/dev.exs                                |  2 +-
 .../middleware/current_actor_provider.ex      |  8 +++++-
 .../middleware/operation_name_logger.ex       | 27 +++++++++++++++++++
 lib/graphql/schema.ex                         |  4 +--
 5 files changed, 38 insertions(+), 5 deletions(-)
 create mode 100644 lib/graphql/middleware/operation_name_logger.ex

diff --git a/config/config.exs b/config/config.exs
index dd5e28b6a..77591db87 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -138,7 +138,7 @@ config :vite_phx,
 config :logger, :console,
   backends: [:console],
   format: "$time $metadata[$level] $message\n",
-  metadata: [:request_id]
+  metadata: [:request_id, :graphql_operation_name, :user_id, :actor_name]
 
 config :mobilizon, Mobilizon.Web.Auth.Guardian,
   issuer: "mobilizon",
diff --git a/config/dev.exs b/config/dev.exs
index 77c55e544..6c8418b88 100644
--- a/config/dev.exs
+++ b/config/dev.exs
@@ -48,7 +48,7 @@ config :mobilizon, Mobilizon.Web.Endpoint,
   ]
 
 # Do not include metadata nor timestamps in development logs
-config :logger, :console, format: "[$level] $message\n", level: :debug
+config :logger, :console, format: "$metadata[$level] $message\n", level: :debug
 
 config :mobilizon, Mobilizon.Service.Geospatial, service: Mobilizon.Service.Geospatial.Nominatim
 
diff --git a/lib/graphql/middleware/current_actor_provider.ex b/lib/graphql/middleware/current_actor_provider.ex
index abf7384cc..64037f233 100644
--- a/lib/graphql/middleware/current_actor_provider.ex
+++ b/lib/graphql/middleware/current_actor_provider.ex
@@ -18,7 +18,13 @@ defmodule Mobilizon.GraphQL.Middleware.CurrentActorProvider do
     case Cachex.fetch(:default_actors, to_string(user_id), fn -> default(user) end) do
       {status, %Actor{preferred_username: preferred_username} = current_actor}
       when status in [:ok, :commit] ->
-        Sentry.Context.set_user_context(%{name: preferred_username})
+        Logger.metadata(user_id: user_id)
+        Logger.metadata(actor_name: "@" <> preferred_username)
+
+        if Application.get_env(:sentry, :dsn) != nil do
+          Sentry.Context.set_user_context(%{name: preferred_username})
+        end
+
         context = Map.put(context, :current_actor, current_actor)
         %Absinthe.Resolution{resolution | context: context}
 
diff --git a/lib/graphql/middleware/operation_name_logger.ex b/lib/graphql/middleware/operation_name_logger.ex
new file mode 100644
index 000000000..7c0a888da
--- /dev/null
+++ b/lib/graphql/middleware/operation_name_logger.ex
@@ -0,0 +1,27 @@
+defmodule Mobilizon.GraphQL.Middleware.OperationNameLogger do
+  @moduledoc """
+  An Absinthe middleware to add to logging providers the GraphQL Operation name as context
+  """
+
+  @behaviour Absinthe.Middleware
+  alias Absinthe.Blueprint.Document.Operation
+
+  def call(resolution, _opts) do
+    case Enum.find(resolution.path, &current_operation?/1) do
+      %Operation{name: name} when not is_nil(name) ->
+        Logger.metadata(graphql_operation_name: name)
+
+        if Application.get_env(:sentry, :dsn) != nil do
+          Sentry.Context.set_extra_context(%{"graphql_operation_name" => name})
+        end
+
+      _ ->
+        Logger.metadata(graphql_operation_name: "#NULL")
+    end
+
+    resolution
+  end
+
+  defp current_operation?(%Operation{current: true}), do: true
+  defp current_operation?(_), do: false
+end
diff --git a/lib/graphql/schema.ex b/lib/graphql/schema.ex
index e89641b4a..8306808d1 100644
--- a/lib/graphql/schema.ex
+++ b/lib/graphql/schema.ex
@@ -20,7 +20,7 @@ defmodule Mobilizon.GraphQL.Schema do
   alias Mobilizon.Actors.{Actor, Follower, Member}
   alias Mobilizon.Discussions.Comment
   alias Mobilizon.Events.{Event, Participant}
-  alias Mobilizon.GraphQL.Middleware.{CurrentActorProvider, ErrorHandler}
+  alias Mobilizon.GraphQL.Middleware.{CurrentActorProvider, ErrorHandler, OperationNameLogger}
   alias Mobilizon.GraphQL.Schema
   alias Mobilizon.GraphQL.Schema.Custom
   alias Mobilizon.Storage.Repo
@@ -199,7 +199,7 @@ defmodule Mobilizon.GraphQL.Schema do
 
   @spec middleware(list(module()), any(), map()) :: list(module())
   def middleware(middleware, _field, %{identifier: type}) when type in [:query, :mutation] do
-    [CurrentActorProvider] ++ middleware ++ [ErrorHandler]
+    [CurrentActorProvider] ++ middleware ++ [ErrorHandler, OperationNameLogger]
   end
 
   def middleware(middleware, _field, _object) do