From 9f61ba2b1d846d5773a75884b10cb8c598164c9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20=C5=9Aliwa?= <39009379+lsliwaradioluz@users.noreply.github.com> Date: Thu, 12 Dec 2024 10:17:35 +0100 Subject: [PATCH] feat(in-4412): logger in magento api (#1559) * chore: remove consola * refactor: replace consola with logger * chore: changeset * Update packages/api-client/src/api/cmsPage/index.ts Co-authored-by: Bartosz Herba * Update packages/api-client/src/api/productDetails/index.ts Co-authored-by: Bartosz Herba * Update packages/api-client/src/api/products/index.ts Co-authored-by: Bartosz Herba * refactor: requestPasswordResetEmail debug log * refactor: reset password debug log * refactor: graphql error logs * refactor: network error log * chore: remove redundant debug log * refactor: invalid token log * refactor: link handlers debug logs --------- Co-authored-by: Bartosz Herba --- .changeset/grumpy-eels-care.md | 5 +++ packages/api-client/package.json | 1 - packages/api-client/src/api/cmsPage/index.ts | 8 ++-- .../src/api/productDetails/index.ts | 8 ++-- packages/api-client/src/api/products/index.ts | 8 ++-- .../api/requestPasswordResetEmail/index.ts | 6 ++- .../api-client/src/api/resetPassword/index.ts | 6 ++- .../src/helpers/magentoLink/graphQl.ts | 21 ++++++---- .../src/helpers/magentoLink/index.ts | 16 +++---- .../src/helpers/magentoLink/linkHandlers.ts | 42 ++++++++++++------- packages/api-client/src/index.server.ts | 10 ++--- yarn.lock | 36 ++++++++++++---- 12 files changed, 108 insertions(+), 59 deletions(-) create mode 100644 .changeset/grumpy-eels-care.md diff --git a/.changeset/grumpy-eels-care.md b/.changeset/grumpy-eels-care.md new file mode 100644 index 000000000..8aa592e82 --- /dev/null +++ b/.changeset/grumpy-eels-care.md @@ -0,0 +1,5 @@ +--- +"@vue-storefront/magento-api": minor +--- + +[CHANGED] Replaced `consola` with Alokai Logger. To learn more about logger, visit [Alokai Logger](https://docs.alokai.com/middleware/guides/logging/). \ No newline at end of file diff --git a/packages/api-client/package.json b/packages/api-client/package.json index 006986be2..2e0505355 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -26,7 +26,6 @@ "@vue-storefront/magento-types": "2.0.0", "@vue-storefront/middleware": "^5.1.0", "agentkeepalive": "^4.2.1", - "consola": "^3.1.0", "dotenv": "^16.0.1", "graphql": "^16.3.0", "graphql-tag": "^2.12.6", diff --git a/packages/api-client/src/api/cmsPage/index.ts b/packages/api-client/src/api/cmsPage/index.ts index 53ec66924..c1123809d 100644 --- a/packages/api-client/src/api/cmsPage/index.ts +++ b/packages/api-client/src/api/cmsPage/index.ts @@ -1,8 +1,8 @@ import { ApolloQueryResult } from "@apollo/client/core"; -import consola from "consola"; import type { CustomHeaders } from "@vue-storefront/magento-types"; import { CmsPageQuery, CmsPageQueryVariables, CustomQuery } from "@vue-storefront/magento-types"; import gql from "graphql-tag"; +import { getLogger } from "@vue-storefront/middleware"; import cmsPageQuery from "./cmsPage"; import { Context } from "../../types/context"; import getHeaders from "../getHeaders"; @@ -71,6 +71,8 @@ export async function cmsPage( customQuery: CustomQuery = { cmsPage: "cmsPage" }, customHeaders: CustomHeaders = {} ): Promise> { + const logger = getLogger(context); + try { const { cmsPage: cmsPageGQL } = context.extendQuery(customQuery, { cmsPage: { @@ -91,7 +93,7 @@ export async function cmsPage( } catch (error) { // For error in data we don't throw 500, because it's not server error if (error.graphQLErrors) { - consola.debug(error); + logger.error(error); return { ...error, @@ -99,7 +101,7 @@ export async function cmsPage( data: null, }; } - consola.error(error); + throw error.networkError?.result || error; } } diff --git a/packages/api-client/src/api/productDetails/index.ts b/packages/api-client/src/api/productDetails/index.ts index 9ad1cb540..a2a4873e5 100644 --- a/packages/api-client/src/api/productDetails/index.ts +++ b/packages/api-client/src/api/productDetails/index.ts @@ -9,7 +9,7 @@ import type { ProductDetailsQueryVariables, } from "@vue-storefront/magento-types"; import gql from "graphql-tag"; -import consola from "consola"; +import { getLogger } from "@vue-storefront/middleware"; import productDetailsQuery from "./productDetailsQuery"; import type { Context } from "../../types/context"; import getHeaders from "../getHeaders"; @@ -111,6 +111,8 @@ export async function productDetails( customQuery: CustomQuery = { productDetails: "productDetails" }, customHeaders: CustomHeaders = {} ): Promise> { + const logger = getLogger(context); + const defaultParams = { pageSize: 10, currentPage: 1, @@ -148,7 +150,7 @@ export async function productDetails( } catch (error) { // For error in data we don't throw 500, because it's not server error if (error.graphQLErrors) { - consola.debug(error); + logger.error(error); return { ...error, @@ -156,7 +158,7 @@ export async function productDetails( data: null, }; } - consola.error(error); + throw error.networkError?.result || error; } } diff --git a/packages/api-client/src/api/products/index.ts b/packages/api-client/src/api/products/index.ts index fce1659ee..da063f50c 100644 --- a/packages/api-client/src/api/products/index.ts +++ b/packages/api-client/src/api/products/index.ts @@ -9,7 +9,7 @@ import { ProductsListQueryVariables, } from "@vue-storefront/magento-types"; import gql from "graphql-tag"; -import consola from "consola"; +import { getLogger } from "@vue-storefront/middleware"; import productsListQuery from "./productsList"; import { Context } from "../../types/context"; import getHeaders from "../getHeaders"; @@ -111,6 +111,8 @@ export async function products( customQuery: CustomQuery = { products: "products" }, customHeaders: CustomHeaders = {} ): Promise> { + const logger = getLogger(context); + const defaultParams = { pageSize: 10, currentPage: 1, @@ -148,7 +150,7 @@ export async function products( } catch (error) { // For error in data we don't throw 500, because it's not server error if (error.graphQLErrors) { - consola.debug(error); + logger.error(error); return { ...error, @@ -156,7 +158,7 @@ export async function products( data: null, }; } - consola.error(error); + throw error.networkError?.result || error; } } diff --git a/packages/api-client/src/api/requestPasswordResetEmail/index.ts b/packages/api-client/src/api/requestPasswordResetEmail/index.ts index 5a0df2ef2..899f65c6c 100644 --- a/packages/api-client/src/api/requestPasswordResetEmail/index.ts +++ b/packages/api-client/src/api/requestPasswordResetEmail/index.ts @@ -3,7 +3,7 @@ import { GraphQLError } from "graphql"; import type { CustomHeaders } from "@vue-storefront/magento-types"; import { RequestPasswordResetEmailMutation, RequestPasswordResetEmailMutationVariables } from "@vue-storefront/magento-types"; import gql from "graphql-tag"; -import consola from "consola"; +import { getLogger } from "@vue-storefront/middleware"; import recaptchaValidator from "../../helpers/recaptcha/recaptchaValidator"; import requestPasswordResetEmailMutation from "./requestPasswordResetEmail"; import { Context } from "../../types/context"; @@ -28,6 +28,8 @@ export async function requestPasswordResetEmail( input: RequestPasswordResetEmailMutationVariables, customHeaders: CustomHeaders = {} ): Promise> { + const logger = getLogger(context); + const { recaptchaToken, ...variables } = input; if (context.config.recaptcha.isEnabled) { @@ -44,7 +46,7 @@ export async function requestPasswordResetEmail( } } - consola.debug("[VSF: Magento] requestPasswordResetEmail", JSON.stringify(input, null, 2)); + logger.debug(`Requesting password reset email with input`, { input }); const result = await context.client.mutate({ mutation: gql` ${requestPasswordResetEmailMutation} diff --git a/packages/api-client/src/api/resetPassword/index.ts b/packages/api-client/src/api/resetPassword/index.ts index 0c23b269c..7b40e5136 100644 --- a/packages/api-client/src/api/resetPassword/index.ts +++ b/packages/api-client/src/api/resetPassword/index.ts @@ -3,7 +3,7 @@ import { GraphQLError } from "graphql"; import type { CustomHeaders } from "@vue-storefront/magento-types"; import { ResetPasswordMutation, ResetPasswordMutationVariables } from "@vue-storefront/magento-types"; import gql from "graphql-tag"; -import consola from "consola"; +import { getLogger } from "@vue-storefront/middleware"; import resetPasswordMutation from "./resetPassword"; import { Context } from "../../types/context"; import recaptchaValidator from "../../helpers/recaptcha/recaptchaValidator"; @@ -30,6 +30,8 @@ export async function resetPassword( input: ResetPasswordMutationVariables, customHeaders: CustomHeaders = {} ): Promise> { + const logger = getLogger(context); + const { recaptchaToken, ...variables } = input; if (context.config.recaptcha.isEnabled) { @@ -46,7 +48,7 @@ export async function resetPassword( } } - consola.debug("[VSF: Magento] requestPasswordResetEmail", JSON.stringify(input, null, 2)); + logger.debug("Initiating password reset request with input", { input }); const result = await context.client.mutate({ mutation: gql` ${resetPasswordMutation} diff --git a/packages/api-client/src/helpers/magentoLink/graphQl.ts b/packages/api-client/src/helpers/magentoLink/graphQl.ts index e114f6cd2..4d877ff05 100644 --- a/packages/api-client/src/helpers/magentoLink/graphQl.ts +++ b/packages/api-client/src/helpers/magentoLink/graphQl.ts @@ -4,7 +4,7 @@ import { onError } from "@apollo/client/link/error"; import { RetryLink } from "@apollo/client/link/retry"; import { setContext } from "@apollo/client/link/context"; import AgentKeepAlive from "agentkeepalive"; -import consola from "consola"; +import { getLogger, type AlokaiContainer } from "@vue-storefront/middleware"; import { handleRetry } from "./linkHandlers"; import { Config } from "../../types/setup"; import possibleTypes from "../../types/possibleTypes.json"; @@ -15,8 +15,10 @@ const agent = new HttpsAgent({ timeout: 30000, }); -const createErrorHandler = () => +const createErrorHandler = (alokai: AlokaiContainer) => onError(({ graphQLErrors, networkError }) => { + const logger = getLogger(alokai); + if (graphQLErrors) { graphQLErrors.forEach(({ message, locations, path, extensions }) => { // Mute all GraphQL authorization errors @@ -26,27 +28,28 @@ const createErrorHandler = () => if (!message.includes("Resource Owner Password Credentials Grant")) { if (!locations) { - consola.error(`[GraphQL error]: Message: ${message}, Path: ${path}`); + logger.error(message, { path }); return; } const parsedLocations = locations.map(({ column, line }) => `[column: ${column}, line: ${line}]`); - consola.error(`[GraphQL error]: Message: ${message}, Location: ${parsedLocations.join(", ")}, Path: ${path}`); + logger.error(message, { path, location: parsedLocations.join(", ") }); } }); } if (networkError) { - consola.error(`[Network error]: ${networkError}`); + logger.error(networkError, { type: "Network Error" }); } }); export const apolloLinkFactory = ( settings: Config, - handlers?: { + handlers: { apolloLink?: ApolloLink; - } + }, + alokai: AlokaiContainer ) => { const baseLink = handlers?.apolloLink || @@ -66,10 +69,10 @@ export const apolloLinkFactory = ( ...settings.customApolloHttpLinkOptions, }); - const onErrorLink = createErrorHandler(); + const onErrorLink = createErrorHandler(alokai); const errorRetry = new RetryLink({ - attempts: handleRetry(), + attempts: handleRetry({ alokai }), delay: () => 0, }); diff --git a/packages/api-client/src/helpers/magentoLink/index.ts b/packages/api-client/src/helpers/magentoLink/index.ts index 96701484f..212bc48dd 100644 --- a/packages/api-client/src/helpers/magentoLink/index.ts +++ b/packages/api-client/src/helpers/magentoLink/index.ts @@ -1,14 +1,16 @@ -import consola from "consola"; +import { type AlokaiContainer } from "@vue-storefront/middleware"; import { Config } from "../../types/setup"; import { apolloLinkFactory } from "./graphQl"; import { linkFactory } from "./linkHandlers"; -export const createMagentoConnection = (settings: Config) => { - consola.debug("createMagentoConnection"); - - const apolloLink = apolloLinkFactory(settings, { - apolloLink: linkFactory({ state: settings.state }), - }); +export const createMagentoConnection = (settings: Config, alokai: AlokaiContainer) => { + const apolloLink = apolloLinkFactory( + settings, + { + apolloLink: linkFactory({ state: settings.state, alokai }), + }, + alokai + ); return { apolloLink, diff --git a/packages/api-client/src/helpers/magentoLink/linkHandlers.ts b/packages/api-client/src/helpers/magentoLink/linkHandlers.ts index 8a88872c2..146f43f08 100644 --- a/packages/api-client/src/helpers/magentoLink/linkHandlers.ts +++ b/packages/api-client/src/helpers/magentoLink/linkHandlers.ts @@ -1,38 +1,48 @@ import { setContext } from "@apollo/client/link/context"; -import consola from "consola"; +import { getLogger, type AlokaiContainer } from "@vue-storefront/middleware"; import { ConfigState } from "../../types/setup"; -export const handleRetry = () => (count, operation, error) => { - if (count > 3) { - return false; - } +export const handleRetry = + ({ alokai }: { alokai: AlokaiContainer }) => + (retryCount, operation, error) => { + const logger = getLogger(alokai); + + if (retryCount > 3) { + return false; + } - if (error?.result?.message === "invalid_token") { - consola.debug(`Apollo retry-link, the operation (${operation.operationName}) sent with wrong token, creating a new one... (attempt: ${count})`); - return true; - } + if (error?.result?.message === "invalid_token") { + const { operationName } = operation; + logger.error(`Invalid token used for operation ${operationName}, Apollo retry-link will refresh the token and retry`, { + operation, + retryCount, + }); + return true; + } - return false; -}; + return false; + }; -export const linkFactory = ({ state }: { state: ConfigState }) => +export const linkFactory = ({ state, alokai }: { state: ConfigState; alokai: AlokaiContainer }) => setContext((apolloReq, { headers }) => { - consola.debug("Apollo linkFactory", apolloReq.operationName); + const logger = getLogger(alokai); + + logger.debug(`Apollo linkFactory ${apolloReq.operationName}`); const Store: string = state.getStore(); const token: string = state.getCustomerToken(); const currency: string = state.getCurrency(); if (currency) { - consola.debug("Apollo currencyLinkFactory, finished, currency: ", currency); + logger.debug(`Finished executing Apollo currencyLinkFactory.`, { currency }); } if (Store) { - consola.debug("Apollo storeLinkFactory, finished, storeId: ", Store); + logger.debug(`Finished executing Apollo storeLinkFactory.`, { Store }); } if (token) { - consola.debug("Apollo authLinkFactory, finished, token: ", token); + logger.debug(`Finished executing Apollo authLinkFactory.`, { token }); } return { diff --git a/packages/api-client/src/index.server.ts b/packages/api-client/src/index.server.ts index aef5c0fc9..72efee2fa 100644 --- a/packages/api-client/src/index.server.ts +++ b/packages/api-client/src/index.server.ts @@ -1,5 +1,5 @@ /* istanbul ignore file */ -import { ApiClientExtension, apiClientFactory } from "@vue-storefront/middleware"; +import { type AlokaiContainer, ApiClientExtension, apiClientFactory } from "@vue-storefront/middleware"; import * as api from "./api"; import { defaultSettings } from "./helpers/apiClient/defaultSettings"; import { createMagentoConnection } from "./helpers/magentoLink"; @@ -13,7 +13,7 @@ const buildConfig = (settings: Config) => state: settings.state || defaultSettings.state, } as unknown as Config); -const init = (settings: Config) => { +const init = (settings: Config, alokai: AlokaiContainer) => { const config = buildConfig(settings); if (settings.client) { @@ -30,7 +30,7 @@ const init = (settings: Config) => { }; } - const { apolloLink } = createMagentoConnection(config); + const { apolloLink } = createMagentoConnection(config, alokai); const client = apolloClientFactory({ link: apolloLink, @@ -52,9 +52,9 @@ const init = (settings: Config) => { }; }; -const onCreate = (settings: Config): { config: Config; client: ClientInstance } => { +const onCreate = (settings: Config, alokai: AlokaiContainer): { config: Config; client: ClientInstance } => { if (!settings?.client) { - return init(settings); + return init(settings, alokai); } const config = buildConfig(settings); diff --git a/yarn.lock b/yarn.lock index 7231183ff..60851014c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3218,11 +3218,6 @@ consola@^3: resolved "https://registrynpm.storefrontcloud.io/consola/-/consola-3.2.3.tgz#0741857aa88cfa0d6fd53f1cff0375136e98502f" integrity sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ== -consola@^3.1.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/consola/-/consola-3.2.2.tgz#be9b295e1e556355a09ac475b4394016144e0c32" - integrity sha512-r921u0vbF4lQsoIqYvSSER+yZLPQGijOHrYcWoCNVNBZmn/bRR+xT/DgerTze/nLD9TTGzdDa378TVhx7RDOYg== - constant-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-3.0.4.tgz#3b84a9aeaf4cf31ec45e6bf5de91bdfb0589faf1" @@ -7236,7 +7231,16 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -7288,7 +7292,14 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -7891,7 +7902,7 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -7909,6 +7920,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"