Merge branch 'graphql-operation-name-logs' into 'main'

Add GraphQL operation name, user ID and actor name in logs

See merge request framasoft/mobilizon!1326
This commit is contained in:
Thomas Citharel 2022-11-06 13:47:59 +00:00
commit da78410039
12 changed files with 74 additions and 37 deletions

View file

@ -138,7 +138,7 @@ config :vite_phx,
config :logger, :console, config :logger, :console,
backends: [:console], backends: [:console],
format: "$time $metadata[$level] $message\n", 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, config :mobilizon, Mobilizon.Web.Auth.Guardian,
issuer: "mobilizon", issuer: "mobilizon",

View file

@ -48,7 +48,7 @@ config :mobilizon, Mobilizon.Web.Endpoint,
] ]
# Do not include metadata nor timestamps in development logs # 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 config :mobilizon, Mobilizon.Service.Geospatial, service: Mobilizon.Service.Geospatial.Nominatim

View file

@ -20,9 +20,9 @@
<div class="flex-1"> <div class="flex-1">
<div class="p-2 flex gap-2"> <div class="p-2 flex gap-2">
<div class=""> <div class="">
<figure class="" v-if="member.parent.avatar"> <figure class="h-12 w-12" v-if="member.parent.avatar">
<img <img
class="rounded-lg" class="rounded-full w-full h-full object-cover"
:src="member.parent.avatar.url" :src="member.parent.avatar.url"
alt="" alt=""
width="48" width="48"

View file

@ -2,7 +2,7 @@ import gql from "graphql-tag";
import { ACTOR_FRAGMENT } from "./actor"; import { ACTOR_FRAGMENT } from "./actor";
export const DASHBOARD = gql` export const DASHBOARD = gql`
query { query Dashboard {
dashboard { dashboard {
lastPublicEventPublished { lastPublicEventPublished {
id id
@ -167,7 +167,7 @@ export const REJECT_RELAY = gql`
`; `;
export const LANGUAGES = gql` export const LANGUAGES = gql`
query { query Languages {
languages { languages {
code code
name name
@ -204,7 +204,7 @@ export const ADMIN_SETTINGS_FRAGMENT = gql`
`; `;
export const ADMIN_SETTINGS = gql` export const ADMIN_SETTINGS = gql`
query { query AdminSettings {
adminSettings { adminSettings {
...adminSettingsFragment ...adminSettingsFragment
} }

View file

@ -27,7 +27,7 @@
paginated paginated
backend-pagination backend-pagination
backend-filtering backend-filtering
:debounce-search="200" :debounce-search="500"
v-model:current-page="page" v-model:current-page="page"
:aria-next-label="t('Next page')" :aria-next-label="t('Next page')"
:aria-previous-label="t('Previous page')" :aria-previous-label="t('Previous page')"
@ -72,9 +72,12 @@
<AccountGroup v-else :size="48" /> <AccountGroup v-else :size="48" />
<div class=""> <div class="">
<div class="prose dark:prose-invert"> <div class="prose dark:prose-invert">
<strong v-if="props.row.name">{{ props.row.name }}</strong <p v-if="props.row.name" class="font-bold mb-0">
><br v-if="props.row.name" /> {{ props.row.name }}
<small>@{{ props.row.preferredUsername }}</small> </p>
<span class="text-sm"
>@{{ props.row.preferredUsername }}</span
>
</div> </div>
</div> </div>
</article> </article>
@ -117,7 +120,7 @@ import {
} from "vue-use-route-query"; } from "vue-use-route-query";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useHead } from "@vueuse/head"; import { useHead } from "@vueuse/head";
import { computed } from "vue"; import { computed, ref } from "vue";
import { Paginate } from "@/types/paginate"; import { Paginate } from "@/types/paginate";
import { IGroup } from "@/types/actor"; import { IGroup } from "@/types/actor";
import AccountGroup from "vue-material-design-icons/AccountGroup.vue"; import AccountGroup from "vue-material-design-icons/AccountGroup.vue";
@ -126,9 +129,10 @@ const PROFILES_PER_PAGE = 10;
const { restrictions } = useRestrictions(); const { restrictions } = useRestrictions();
const preferredUsername = useRouteQuery("preferredUsername", ""); const preferredUsername = ref("");
const name = useRouteQuery("name", ""); const name = ref("");
const domain = useRouteQuery("domain", ""); const domain = ref("");
const local = useRouteQuery("local", false, booleanTransformer); const local = useRouteQuery("local", false, booleanTransformer);
const suspended = useRouteQuery("suspended", false, booleanTransformer); const suspended = useRouteQuery("suspended", false, booleanTransformer);
const page = useRouteQuery("page", 1, integerTransformer); const page = useRouteQuery("page", 1, integerTransformer);

View file

@ -20,7 +20,7 @@
paginated paginated
backend-pagination backend-pagination
backend-filtering backend-filtering
:debounce-search="200" :debounce-search="500"
v-model:current-page="page" v-model:current-page="page"
:aria-next-label="t('Next page')" :aria-next-label="t('Next page')"
:aria-previous-label="t('Previous page')" :aria-previous-label="t('Previous page')"
@ -102,7 +102,7 @@ import RouteName from "@/router/name";
import EmptyContent from "@/components/Utils/EmptyContent.vue"; import EmptyContent from "@/components/Utils/EmptyContent.vue";
import { useQuery } from "@vue/apollo-composable"; import { useQuery } from "@vue/apollo-composable";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { computed } from "vue"; import { computed, ref } from "vue";
import { useHead } from "@vueuse/head"; import { useHead } from "@vueuse/head";
import { import {
useRouteQuery, useRouteQuery,
@ -115,9 +115,10 @@ import Account from "vue-material-design-icons/Account.vue";
const PROFILES_PER_PAGE = 10; const PROFILES_PER_PAGE = 10;
const preferredUsername = useRouteQuery("preferredUsername", ""); const preferredUsername = ref("");
const name = useRouteQuery("name", ""); const name = ref("");
const domain = useRouteQuery("domain", ""); const domain = ref("");
const local = useRouteQuery("local", false, booleanTransformer); const local = useRouteQuery("local", false, booleanTransformer);
const suspended = useRouteQuery("suspended", false, booleanTransformer); const suspended = useRouteQuery("suspended", false, booleanTransformer);
const page = useRouteQuery("page", 1, integerTransformer); const page = useRouteQuery("page", 1, integerTransformer);

View file

@ -1,9 +1,9 @@
<template> <template>
<section class="container mx-auto"> <section class="container mx-auto">
<h1 class="title">{{ $t("My groups") }}</h1> <h1 class="title">{{ t("My groups") }}</h1>
<p> <p>
{{ {{
$t( t(
"Groups are spaces for coordination and preparation to better organize events and manage your community." "Groups are spaces for coordination and preparation to better organize events and manage your community."
) )
}} }}
@ -13,7 +13,7 @@
tag="router-link" tag="router-link"
variant="primary" variant="primary"
:to="{ name: RouteName.CREATE_GROUP }" :to="{ name: RouteName.CREATE_GROUP }"
>{{ $t("Create group") }}</o-button >{{ t("Create group") }}</o-button
> >
</div> </div>
<o-loading v-model:active="loading"></o-loading> <o-loading v-model:active="loading"></o-loading>
@ -35,10 +35,10 @@
v-show="membershipsPages.total > limit" v-show="membershipsPages.total > limit"
v-model="page" v-model="page"
:per-page="limit" :per-page="limit"
:aria-next-label="$t('Next page')" :aria-next-label="t('Next page')"
:aria-previous-label="$t('Previous page')" :aria-previous-label="t('Previous page')"
:aria-page-label="$t('Page')" :aria-page-label="t('Page')"
:aria-current-label="$t('Current page')" :aria-current-label="t('Current page')"
> >
</o-pagination> </o-pagination>
</section> </section>
@ -51,7 +51,7 @@
<div class="img-container" :class="{ webp: supportsWebPFormat }" /> <div class="img-container" :class="{ webp: supportsWebPFormat }" />
<div class="text-center"> <div class="text-center">
<p> <p>
{{ $t("You are not part of any group.") }} {{ t("You are not part of any group.") }}
<i18n-t <i18n-t
keypath="Do you wish to {create_group} or {explore_groups}?" keypath="Do you wish to {create_group} or {explore_groups}?"
> >
@ -59,14 +59,14 @@
<o-button <o-button
tag="router-link" tag="router-link"
:to="{ name: RouteName.CREATE_GROUP }" :to="{ name: RouteName.CREATE_GROUP }"
>{{ $t("create a group") }}</o-button >{{ t("create a group") }}</o-button
> >
</template> </template>
<template #explore_groups> <template #explore_groups>
<o-button <o-button
tag="router-link" tag="router-link"
:to="{ name: RouteName.SEARCH }" :to="{ name: RouteName.SEARCH }"
>{{ $t("explore the groups") }}</o-button >{{ t("explore the groups") }}</o-button
> >
</template> </template>
</i18n-t> </i18n-t>

View file

@ -21,11 +21,11 @@
> >
<div class="flex gap-1"> <div class="flex gap-1">
<div class="flex gap-1"> <div class="flex gap-1">
<figure class="" v-if="log.actor?.avatar"> <figure class="h-10 w-10" v-if="log.actor?.avatar">
<img <img
alt="" alt=""
:src="log.actor.avatar?.url" :src="log.actor.avatar?.url"
class="rounded-full" class="object-cover rounded-full h-full w-full"
width="36" width="36"
height="36" height="36"
/> />

View file

@ -36,8 +36,7 @@ defmodule Mobilizon.Federation.ActivityPub.Actions.Update do
{:ok, activity, entity} {:ok, activity, entity}
{:error, err} -> {:error, err} ->
Logger.error("Something went wrong while creating an activity") Logger.error("Something went wrong while creating an activity", err: inspect(err))
Logger.debug(inspect(err))
{:error, err} {:error, err}
end end
end end

View file

@ -18,7 +18,13 @@ defmodule Mobilizon.GraphQL.Middleware.CurrentActorProvider do
case Cachex.fetch(:default_actors, to_string(user_id), fn -> default(user) end) do case Cachex.fetch(:default_actors, to_string(user_id), fn -> default(user) end) do
{status, %Actor{preferred_username: preferred_username} = current_actor} {status, %Actor{preferred_username: preferred_username} = current_actor}
when status in [:ok, :commit] -> when status in [:ok, :commit] ->
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}) Sentry.Context.set_user_context(%{name: preferred_username})
end
context = Map.put(context, :current_actor, current_actor) context = Map.put(context, :current_actor, current_actor)
%Absinthe.Resolution{resolution | context: context} %Absinthe.Resolution{resolution | context: context}

View file

@ -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

View file

@ -20,7 +20,7 @@ defmodule Mobilizon.GraphQL.Schema do
alias Mobilizon.Actors.{Actor, Follower, Member} alias Mobilizon.Actors.{Actor, Follower, Member}
alias Mobilizon.Discussions.Comment alias Mobilizon.Discussions.Comment
alias Mobilizon.Events.{Event, Participant} 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
alias Mobilizon.GraphQL.Schema.Custom alias Mobilizon.GraphQL.Schema.Custom
alias Mobilizon.Storage.Repo alias Mobilizon.Storage.Repo
@ -199,7 +199,7 @@ defmodule Mobilizon.GraphQL.Schema do
@spec middleware(list(module()), any(), map()) :: list(module()) @spec middleware(list(module()), any(), map()) :: list(module())
def middleware(middleware, _field, %{identifier: type}) when type in [:query, :mutation] do def middleware(middleware, _field, %{identifier: type}) when type in [:query, :mutation] do
[CurrentActorProvider] ++ middleware ++ [ErrorHandler] [CurrentActorProvider] ++ middleware ++ [ErrorHandler, OperationNameLogger]
end end
def middleware(middleware, _field, _object) do def middleware(middleware, _field, _object) do