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:
commit
da78410039
@ -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",
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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>
|
||||||
|
@ -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"
|
||||||
/>
|
/>
|
||||||
|
@ -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
|
||||||
|
@ -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] ->
|
||||||
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)
|
context = Map.put(context, :current_actor, current_actor)
|
||||||
%Absinthe.Resolution{resolution | context: context}
|
%Absinthe.Resolution{resolution | context: context}
|
||||||
|
|
||||||
|
27
lib/graphql/middleware/operation_name_logger.ex
Normal file
27
lib/graphql/middleware/operation_name_logger.ex
Normal 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, ¤t_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
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user