From 4e3e92c7200e125101fe552abfdc8cb9cac2be4e Mon Sep 17 00:00:00 2001 From: Josh Faigan Date: Tue, 8 Oct 2024 14:40:10 -0400 Subject: [PATCH] add status codes and event methods to log requests This commit moves the logRequestLine function into a separate file and adds status codes and event methods. It grabs both get and post requests --- .../src/cli/utilities/log-request-line.ts | 38 +++++++++++++++++++ .../cli/utilities/theme-environment/html.ts | 23 +---------- .../cli/utilities/theme-environment/proxy.ts | 25 ++++++++++++ packages/theme/src/cli/utilities/theme-fs.ts | 4 +- 4 files changed, 66 insertions(+), 24 deletions(-) create mode 100644 packages/theme/src/cli/utilities/log-request-line.ts diff --git a/packages/theme/src/cli/utilities/log-request-line.ts b/packages/theme/src/cli/utilities/log-request-line.ts new file mode 100644 index 00000000000..c74d66788a6 --- /dev/null +++ b/packages/theme/src/cli/utilities/log-request-line.ts @@ -0,0 +1,38 @@ +import {timestampDateFormat} from '../constants.js' +import {Response as CliKitResponse} from '@shopify/cli-kit/node/http' +import {outputContent, outputInfo, outputToken} from '@shopify/cli-kit/node/output' +import {H3Event} from 'h3' + +const CHARACTER_TRUNCATION_LIMIT = 80 + +export function logRequestLine(event: H3Event, response: CliKitResponse | Response) { + const truncatedPath = + event.path.length > CHARACTER_TRUNCATION_LIMIT + ? `${event.path.substring(0, CHARACTER_TRUNCATION_LIMIT)}...` + : event.path + const serverTiming = response.headers.get('server-timing') + const requestDuration = serverTiming?.match(/cfRequestDuration;dur=([\d.]+)/)?.[1] + const durationString = requestDuration ? `${Math.round(Number(requestDuration))}ms` : '' + + const statusColor = getColorizeStatus(response.status) + + const eventMethodAligned = event.method.padStart(6) + + outputInfo( + outputContent`• ${timestampDateFormat.format(new Date())} Request ${outputToken.raw( + '»', + )} ${eventMethodAligned} ${truncatedPath} ${statusColor(String(response.status))} ${outputToken.gray( + `${durationString}`, + )}`, + ) +} + +function getColorizeStatus(status: number) { + if (status < 300) { + return outputToken.green + } else if (status < 400) { + return outputToken.yellow + } else { + return outputToken.errorText + } +} diff --git a/packages/theme/src/cli/utilities/theme-environment/html.ts b/packages/theme/src/cli/utilities/theme-environment/html.ts index 56cc4c86f47..8e6097da653 100644 --- a/packages/theme/src/cli/utilities/theme-environment/html.ts +++ b/packages/theme/src/cli/utilities/theme-environment/html.ts @@ -2,17 +2,14 @@ import {getProxyStorefrontHeaders, patchRenderingResponse} from './proxy.js' import {getInMemoryTemplates, injectHotReloadScript} from './hot-reload/server.js' import {render} from './storefront-renderer.js' import {getExtensionInMemoryTemplates} from '../theme-ext-environment/theme-ext-server.js' -import {timestampDateFormat} from '../../constants.js' -import {defineEventHandler, getCookie, H3Event, setResponseHeader, setResponseStatus, type H3Error} from 'h3' +import {logRequestLine} from '../log-request-line.js' +import {defineEventHandler, getCookie, setResponseHeader, setResponseStatus, type H3Error} from 'h3' import {renderError, renderFatalError} from '@shopify/cli-kit/node/ui' -import {outputContent, outputInfo, outputToken} from '@shopify/cli-kit/node/output' import {AbortError} from '@shopify/cli-kit/node/error' import type {Response} from '@shopify/cli-kit/node/http' import type {Theme} from '@shopify/cli-kit/node/themes/types' import type {DevServerContext} from './types.js' -const CHARACTER_TRUNCATION_LIMIT = 80 - export function getHtmlHandler(theme: Theme, ctx: DevServerContext) { return defineEventHandler((event) => { const [browserPathname = '/', browserSearch = ''] = event.path.split('?') @@ -68,22 +65,6 @@ export function getHtmlHandler(theme: Theme, ctx: DevServerContext) { }) } -function logRequestLine(event: H3Event, response: Response) { - const truncatedPath = - event.path.length > CHARACTER_TRUNCATION_LIMIT - ? `${event.path.substring(0, CHARACTER_TRUNCATION_LIMIT)}...` - : event.path - const serverTiming = response.headers.get('server-timing') - const requestDuration = serverTiming?.match(/cfRequestDuration;dur=([\d.]+)/)?.[1] - const durationString = requestDuration ? `${Math.round(Number(requestDuration))}ms` : '' - - outputInfo( - outputContent`• ${timestampDateFormat.format(new Date())} Request ${outputToken.raw('»')} ${outputToken.gray( - `${event.method} ${truncatedPath} ${durationString}`, - )}`, - ) -} - function getErrorPage(options: {title: string; header: string; message: string; code: string}) { const html = String.raw diff --git a/packages/theme/src/cli/utilities/theme-environment/proxy.ts b/packages/theme/src/cli/utilities/theme-environment/proxy.ts index 76dab088090..593124eb9ab 100644 --- a/packages/theme/src/cli/utilities/theme-environment/proxy.ts +++ b/packages/theme/src/cli/utilities/theme-environment/proxy.ts @@ -1,4 +1,5 @@ import {buildCookies} from './storefront-renderer.js' +import {logRequestLine} from '../log-request-line.js' import {renderWarning} from '@shopify/cli-kit/node/ui' import { defineEventHandler, @@ -85,6 +86,20 @@ export function canProxyRequest(event: H3Event) { return Boolean(extension) || acceptsType !== '*/*' } +function shouldLog(event: H3Event) { + const ignoredPathPrefixes = [EXTENSION_CDN_PREFIX, VANITY_CDN_PREFIX, '/checkouts', '/payments'] + const ignoredExtensions = ['.js', '.css', '.json', '.map'] + + if (ignoredPathPrefixes.some((prefix) => event.path.startsWith(prefix))) return false + + const [pathname] = event.path.split('?') as [string] + const extension = extname(pathname) + + if (ignoredExtensions.includes(extension)) return false + + return true +} + function getStoreFqdnForRegEx(ctx: DevServerContext) { return ctx.session.storeFqdn.replaceAll('.', '\\.') } @@ -254,6 +269,16 @@ function proxyStorefrontRequest(event: H3Event, ctx: DevServerContext) { redirect: 'manual', }, async onResponse(event, response) { + if ( + !event.path.startsWith(EXTENSION_CDN_PREFIX) && + !event.path.startsWith(VANITY_CDN_PREFIX) && + !event.path.endsWith('.js') + ) { + if (shouldLog(event)) { + logRequestLine(event, response) + } + } + patchProxiedResponseHeaders(ctx, event, response) const fileName = url.pathname.split('/').at(-1) diff --git a/packages/theme/src/cli/utilities/theme-fs.ts b/packages/theme/src/cli/utilities/theme-fs.ts index bf125bbe6e1..c64e3de6d3c 100644 --- a/packages/theme/src/cli/utilities/theme-fs.ts +++ b/packages/theme/src/cli/utilities/theme-fs.ts @@ -398,8 +398,6 @@ function dirPath(filePath: string) { function outputSyncResult(action: 'update' | 'delete', fileKey: string): void { outputInfo( - outputContent`• ${timestampDateFormat.format(new Date())} Synced ${outputToken.raw('»')} ${outputToken.gray( - `${action} ${fileKey}`, - )}`, + outputContent`• ${timestampDateFormat.format(new Date())} Synced ${outputToken.raw('»')} ${action} ${fileKey}`, ) }