Skip to content

Commit 4807b50

Browse files
committed
feat: unify server monitors usage, add logger for data loader
1 parent 721d9c1 commit 4807b50

File tree

16 files changed

+72
-85
lines changed

16 files changed

+72
-85
lines changed

.changeset/great-wolves-flash.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@modern-js/runtime': patch
3+
'@modern-js/prod-server': patch
4+
'@modern-js/server-core': patch
5+
---
6+
7+
feat: unify server monitors usage, add logger for data loader

packages/runtime/plugin-runtime/src/core/server/requestHandler.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { createLoaderManager } from '../loader/loaderManager';
2020
import { createRoot } from '../react';
2121
import type { SSRServerContext } from '../types';
2222
import { CHUNK_CSS_PLACEHOLDER } from './constants';
23+
import { SSRErrors } from './tracer';
2324
import { getSSRConfigByEntry, getSSRMode } from './utils';
2425

2526
export type { RequestHandlerConfig as HandleRequestConfig } from '@modern-js/app-tools';
@@ -234,6 +235,14 @@ export const createRequestHandler: CreateRequestHandler = async (
234235
context.ssrContext?.response.status(context.routerContext?.statusCode);
235236
}
236237

238+
// log error by monitors when data loader throw error
239+
const errors = Object.values(
240+
(context.routerContext?.errors || {}) as Record<string, Error>,
241+
);
242+
if (errors.length > 0) {
243+
options.onError(errors[0], SSRErrors.LOADER_ERROR);
244+
}
245+
237246
context.initialData = initialData;
238247

239248
const redirectResponse = getRedirectResponse(initialData);

packages/runtime/plugin-runtime/src/core/server/stream/createReadableStream.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import checkIsBot from 'isbot';
44
import { ServerStyleSheet } from 'styled-components';
55
import { ESCAPED_SHELL_STREAM_END_MARK } from '../../../common';
66
import { RenderLevel } from '../../constants';
7+
import { SSRErrors } from '../tracer';
78
import {
89
type CreateReadableStreamFromElement,
910
ShellChunkStatus,
@@ -117,13 +118,12 @@ export const createReadableStreamFromElement: CreateReadableStreamFromElement =
117118

118119
const readableStream = getReadableStreamFromString(fallbackHtml);
119120
resolve(readableStream);
120-
options?.onShellError?.(error);
121+
options.onShellError?.(error);
121122
});
122123
},
123124
onError(error: unknown) {
124125
renderLevel = RenderLevel.CLIENT_RENDER;
125-
126-
options?.onError?.(error);
126+
options.onError(error);
127127
},
128128
});
129129
});

packages/runtime/plugin-runtime/src/core/server/stream/createReadableStream.worker.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ export const createReadableStreamFromElement: CreateReadableStreamFromElement =
4040
nonce: config.nonce,
4141
rscRoot,
4242
onError(error: unknown) {
43-
options.onError?.(error);
43+
// TODO: add error key
44+
options.onError(error);
4445
},
4546
});
4647

packages/runtime/plugin-runtime/src/core/server/stream/shared.tsx

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { OnError } from '@modern-js/app-tools';
12
import { run } from '@modern-js/runtime-utils/node';
23
import { time } from '@modern-js/runtime-utils/time';
34
import { parseHeaders } from '@modern-js/runtime-utils/universal/request';
@@ -11,12 +12,7 @@ import type { RuntimeContext } from '../../context';
1112
import { wrapRuntimeContextProvider } from '../../react/wrapper';
1213
import type { HandleRequestConfig } from '../requestHandler';
1314
import type { RenderStreaming, SSRConfig } from '../shared';
14-
import {
15-
SSRErrors,
16-
SSRTimings,
17-
createOnError,
18-
createOnTiming,
19-
} from '../tracer';
15+
import { SSRErrors, SSRTimings } from '../tracer';
2016
import { getSSRConfigByEntry } from '../utils';
2117

2218
export type CreateReadableStreamFromElementOptions = {
@@ -33,7 +29,7 @@ export type CreateReadableStreamFromElementOptions = {
3329
onShellReady?: () => void;
3430
onShellError?: (error: unknown) => void;
3531
onAllReady?: () => void;
36-
onError?: (error: unknown) => void;
32+
onError: OnError;
3733
};
3834

3935
export type CreateReadableStreamFromElement = (
@@ -79,9 +75,7 @@ export function createRenderStreaming(
7975
return run(headersData, async () => {
8076
const end = time();
8177
const { runtimeContext, config, resource } = options;
82-
83-
const onError = createOnError(options.onError);
84-
const onTiming = createOnTiming(options.onTiming);
78+
const { onError, onTiming } = options;
8579

8680
const { htmlTemplate, entryName } = resource;
8781

@@ -124,10 +118,10 @@ export function createRenderStreaming(
124118
onTiming(SSRTimings.RENDER_HTML, cost);
125119
},
126120
onShellError(error) {
127-
onError(SSRErrors.RENDER_SHELL, error);
121+
onError(error, SSRErrors.RENDER_SHELL);
128122
},
129123
onError(error) {
130-
onError(SSRErrors.RENDER_STREAM, error);
124+
onError(error, SSRErrors.RENDER_STREAM);
131125
},
132126
},
133127
);

packages/runtime/plugin-runtime/src/core/server/string/index.ts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { OnError, OnTiming } from '@modern-js/app-tools';
12
import { run } from '@modern-js/runtime-utils/node';
23
import type { StaticHandlerContext } from '@modern-js/runtime-utils/remix-router';
34
import { time } from '@modern-js/runtime-utils/time';
@@ -15,13 +16,7 @@ import {
1516
} from '../constants';
1617
import { createReplaceHelemt } from '../helmet';
1718
import { type BuildHtmlCb, type RenderString, buildHtml } from '../shared';
18-
import {
19-
SSRErrors,
20-
SSRTimings,
21-
type Tracer,
22-
createOnError,
23-
createOnTiming,
24-
} from '../tracer';
19+
import { SSRErrors, SSRTimings, type Tracer } from '../tracer';
2520
import { getSSRConfigByEntry, safeReplace } from '../utils';
2621
import { LoadableCollector } from './loadable';
2722
import { prefetch } from './prefetch';
@@ -39,10 +34,7 @@ export const renderString: RenderString = async (
3934
return run(headersData, async () => {
4035
const { resource, runtimeContext, config, onError, onTiming } = options;
4136

42-
const tracer: Tracer = {
43-
onError: createOnError(onError),
44-
onTiming: createOnTiming(onTiming),
45-
};
37+
const tracer: Tracer = { onError, onTiming };
4638

4739
const routerContext = runtimeContext.routerContext as StaticHandlerContext;
4840

@@ -74,7 +66,7 @@ export const renderString: RenderString = async (
7466
chunkSet.renderLevel = RenderLevel.SERVER_PREFETCH;
7567
} catch (e) {
7668
chunkSet.renderLevel = RenderLevel.CLIENT_RENDER;
77-
tracer.onError(SSRErrors.PRERENDER, e);
69+
tracer.onError(e, SSRErrors.PRERENDER);
7870
}
7971

8072
const collectors = [
@@ -146,7 +138,7 @@ async function generateHtml(
146138
onTiming(SSRTimings.RENDER_HTML, cost);
147139
} catch (e) {
148140
chunkSet.renderLevel = RenderLevel.CLIENT_RENDER;
149-
onError(SSRErrors.RENDER_HTML, e);
141+
onError(e, SSRErrors.RENDER_HTML);
150142
}
151143

152144
// collectors do effect

packages/runtime/plugin-runtime/src/core/server/string/prefetch.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export const prefetch = async (
5757
// tracker.trackTiming(SSRTimings.PRERENDER, cost);
5858
} catch (e) {
5959
const error = e as Error;
60-
onError(SSRErrors.PRERENDER, error);
60+
onError(error, SSRErrors.PRERENDER);
6161

6262
// re-throw the error
6363
throw e;
@@ -81,7 +81,7 @@ export const prefetch = async (
8181

8282
onTiming(SSRTimings.USE_LOADER, cost);
8383
} catch (e) {
84-
onError(SSRErrors.USE_LOADER, e);
84+
onError(e, SSRErrors.USE_LOADER);
8585

8686
// re-throw the error
8787
throw e;
@@ -90,7 +90,7 @@ export const prefetch = async (
9090
Object.keys(loadersData).forEach(id => {
9191
const data = loadersData[id];
9292
if (data._error) {
93-
onError(SSRErrors.USE_LOADER, data._error);
93+
onError(data._error, SSRErrors.USE_LOADER);
9494
delete data._error;
9595
}
9696
});
Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { OnError, OnTiming } from '@modern-js/app-tools';
2+
13
export enum SSRTimings {
24
PRERENDER = 'ssr-prerender',
35
RENDER_HTML = 'ssr-render-html',
@@ -11,30 +13,10 @@ export enum SSRErrors {
1113
RENDER_HTML = 'App Render To HTML',
1214
RENDER_STREAM = 'An error occurs during streaming SSR',
1315
RENDER_SHELL = 'An error occurs during streaming render shell',
16+
LOADER_ERROR = 'App error occurs during data loader',
1417
}
1518

1619
export type Tracer = {
1720
onError: OnError;
1821
onTiming: OnTiming;
1922
};
20-
21-
export type OnError = (key: SSRErrors, e: unknown) => void;
22-
23-
export function createOnError(onError?: (e: unknown) => void): OnError {
24-
return (key, e) => {
25-
const error = e instanceof Error ? e : new Error('Unexpected Server Error');
26-
27-
(error as any).name = key;
28-
29-
onError?.(e);
30-
};
31-
}
32-
export type OnTiming = (key: SSRTimings, cost: number) => void;
33-
34-
export function createOnTiming(
35-
onTiming?: (name: string, dur: number) => void,
36-
): OnTiming {
37-
return (key, cost) => {
38-
onTiming?.(key, cost);
39-
};
40-
}

packages/runtime/plugin-runtime/src/core/types.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { OnError, OnTiming } from '@modern-js/app-tools';
12
import type { BaseSSRServerContext } from '@modern-js/types';
23
import type { RenderLevel } from './constants';
34
import type { LoaderResult } from './loader/loaderManager';
@@ -68,8 +69,8 @@ export type SSRServerContext = Pick<
6869
};
6970
htmlModifiers: BuildHtmlCb[];
7071
loaderFailureMode?: 'clientRender' | 'errorBoundary';
71-
onError?: (e: unknown) => void;
72-
onTiming?: (name: string, dur: number) => void;
72+
onError: OnError;
73+
onTiming: OnTiming;
7374
useJsonScript?: boolean;
7475
};
7576

packages/server/core/src/plugins/render/render.ts

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { IncomingMessage } from 'http';
2-
import type { Logger, Metrics, Reporter, ServerRoute } from '@modern-js/types';
2+
import type { ServerRoute } from '@modern-js/types';
33
import { cutNameByHyphen } from '@modern-js/utils/universal';
44
import type { Router } from 'hono/router';
55
import { TrieRouter } from 'hono/router/trie-router';
6-
import { REPLACE_REG, X_MODERNJS_RENDER } from '../../constants';
6+
import { X_MODERNJS_RENDER } from '../../constants';
77
import type {
88
CacheConfig,
99
FallbackReason,
@@ -18,11 +18,9 @@ import {
1818
createErrorHtml,
1919
getPathname,
2020
getRuntimeEnv,
21-
onError as onErrorFn,
2221
parseHeaders,
2322
parseQuery,
2423
sortRoutes,
25-
transformResponse,
2624
} from '../../utils';
2725
import { dataHandler } from './dataHandler';
2826
import { renderRscHandler } from './renderRscHandler';
@@ -41,6 +39,11 @@ interface CreateRenderOptions {
4139
nonce?: string;
4240
}
4341

42+
type FallbackWrapper = (
43+
reason: FallbackReason,
44+
err?: unknown,
45+
) => ReturnType<OnFallback>;
46+
4447
const DYNAMIC_ROUTE_REG = /\/:./;
4548

4649
function getRouter(routes: ServerRoute[]): Router<ServerRoute> {
@@ -113,7 +116,7 @@ export async function createRender({
113116
cacheConfig,
114117
forceCSR,
115118
config,
116-
onFallback: onFallbackFn,
119+
onFallback,
117120
}: CreateRenderOptions): Promise<Render> {
118121
const router = getRouter(routes);
119122

@@ -146,9 +149,9 @@ export async function createRender({
146149
const fallbackHeader = `x-${cutNameByHyphen(framework)}-ssr-fallback`;
147150
let fallbackReason = null;
148151

149-
const onFallback = async (reason: FallbackReason, error?: unknown) => {
152+
const fallbackWrapper: FallbackWrapper = async (reason, error?) => {
150153
fallbackReason = reason;
151-
return onFallbackFn?.(reason, { logger, reporter, metrics }, error);
154+
return onFallback?.(reason, { logger, reporter, metrics }, error);
152155
};
153156

154157
if (!routeInfo) {
@@ -176,15 +179,15 @@ export async function createRender({
176179
routeInfo.isSSR,
177180
forceCSR,
178181
nodeReq,
179-
onFallback,
182+
fallbackWrapper,
180183
);
181184

182185
const headerData = parseHeaders(req);
183186

184-
const onError = (e: unknown) => {
187+
const onError = (e: unknown, key?: string) => {
185188
monitors?.error(
186189
`SSR Error - ${
187-
e instanceof Error ? e.name : e
190+
key || (e instanceof Error ? e.name : e)
188191
}, error = %s, req.url = %s, req.headers = %o`,
189192
e instanceof Error ? e.stack || e.message : e,
190193
forMatchpathname,
@@ -196,11 +199,6 @@ export async function createRender({
196199
monitors?.timing(name, dur, 'SSR');
197200
};
198201

199-
const onBoundError = async (e: unknown) => {
200-
onErrorFn(ErrorDigest.ERENDER, e as string | Error, monitors, req);
201-
await onFallback?.('error', e);
202-
};
203-
204202
const renderOptions: SSRRenderOptions & {
205203
serverRoutes: ServerRoute[];
206204
} = {
@@ -232,7 +230,7 @@ export async function createRender({
232230
case 'data':
233231
response =
234232
(await dataHandler(req, renderOptions)) ||
235-
(await renderHandler(req, renderOptions, 'ssr', onBoundError));
233+
(await renderHandler(req, renderOptions, 'ssr', fallbackWrapper));
236234
break;
237235
case 'rsc-tree':
238236
response = await renderRscHandler(req, renderOptions);
@@ -246,7 +244,7 @@ export async function createRender({
246244
req,
247245
renderOptions,
248246
renderMode,
249-
onBoundError,
247+
fallbackWrapper,
250248
);
251249
break;
252250
default:
@@ -264,7 +262,7 @@ async function renderHandler(
264262
request: Request,
265263
options: SSRRenderOptions,
266264
mode: 'ssr' | 'csr',
267-
onError: (e: unknown) => Promise<void>,
265+
fallbackWrapper: FallbackWrapper,
268266
) {
269267
let response: Response | null = null;
270268

@@ -315,7 +313,8 @@ async function renderHandler(
315313
try {
316314
response = await ssrRender(request, options);
317315
} catch (e) {
318-
await onError(e);
316+
options.onError(e as Error, ErrorDigest.ERENDER);
317+
await fallbackWrapper('error', e);
319318
response = csrRender(options.html);
320319
}
321320
} else {
@@ -340,7 +339,7 @@ async function getRenderMode(
340339
isSSR?: boolean,
341340
forceCSR?: boolean,
342341
nodeReq?: IncomingMessage,
343-
onFallback?: (reason: FallbackReason, err?: unknown) => Promise<void>,
342+
onFallback?: FallbackWrapper,
344343
): Promise<'ssr' | 'csr' | 'data' | 'rsc-action' | 'rsc-tree'> {
345344
const query = parseQuery(req);
346345
if (req.headers.get('x-rsc-action')) {

packages/server/core/src/plugins/render/ssrRender.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ export interface SSRRenderOptions {
4141
cacheConfig?: CacheConfig;
4242
nodeReq?: IncomingMessage;
4343

44-
onError?: OnError;
45-
onTiming?: OnTiming;
44+
onError: OnError;
45+
onTiming: OnTiming;
4646
}
4747

4848
const SERVER_RUNTIME_ENTRY = 'requestHandler';

0 commit comments

Comments
 (0)