create-t3-app
create-t3-app copied to clipboard
feat: persist trpc logs in prod
Provide environment information
System:
OS: Linux 5.4 Ubuntu 20.04.5 LTS (Focal Fossa)
CPU: (2) x64 Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz
Memory: 1.16 GB / 3.84 GB
Container: Yes
Shell: 5.0.17 - /bin/bash
Binaries:
Node: 16.18.1 - ~/nvm/current/bin/node
Yarn: 1.22.19 - /usr/bin/yarn
npm: 8.19.2 - ~/nvm/current/bin/npm
"initVersion": "6.11.2"
Describe the bug
An application is generated by create-t3-app.
Under development, when a tRPC endpoint encounters an error, there is a log in the console output, although there is no stack trace (the stack trace can be obtained by inspecting the response body).
❌ tRPC failed on example.hello: TRPCError: Cannot read properties of undefined (reading 'this is a programmer error')
When the app is built for production, when a tRPC endpoint encounters an error, the error is not printed to the console. The stack trace is not in the response body either (presumably for security reasons). This makes it hard for developers to troubleshoot the problem by looking at server’s logs, as no stack trace or any trace of error is output to the console.
To reproduce
Update src/server/trpc/router/example.ts and inject some programmer error into it.
diff --git a/src/server/trpc/router/example.ts b/src/server/trpc/router/example.ts
index b736705..ccbfb81 100644
--- a/src/server/trpc/router/example.ts
+++ b/src/server/trpc/router/example.ts
@@ -6,6 +6,7 @@ export const exampleRouter = router({
hello: publicProcedure
.input(z.object({ text: z.string().nullish() }).nullish())
.query(({ input }) => {
+ void (undefined as any)["this is a programmer error"];
return {
greeting: `Hello ${input?.text ?? "world"}`,
};
Run yarn build and env NODE_ENV=production yarn start. Go to http://localhost:3000/ and let the frontend request data from tRPC.
Additional information
It seems that the tRPC error handler is added in this PR:
- https://github.com/t3-oss/create-t3-app/pull/413
However it is only enabled in development mode. I think this should be enabled in production mode as well, as I think the current behavior is not a good default.
I have never seen any backend setup that doesn’t print an error stack trace to the console when an error occurs. This behavior of silently discarding errors is very surprising to me.
Express, Fastify, and Next.js all have error logging enabled in production. For example, here’s a faulty Next.js API route:
// src/pages/api/crash.ts
import { type NextApiRequest, type NextApiResponse } from "next";
const crash = async (req: NextApiRequest, res: NextApiResponse) => {
void (undefined as any)["this is a programmer error"];
res.send('ok')
};
export default crash;
At least, when there is an error in production, a stack trace is printed to the console:
TypeError: Cannot read properties of undefined (reading 'this is a programmer error')
at crash (/workspaces/fresh-t3-app/.next/server/pages/api/crash.js:16:19)
at Object.apiResolver (/workspaces/fresh-t3-app/node_modules/next/dist/server/api-utils/node.js:367:15)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async NextNodeServer.runApi (/workspaces/fresh-t3-app/node_modules/next/dist/server/next-server.js:476:9)
at async Object.fn (/workspaces/fresh-t3-app/node_modules/next/dist/server/next-server.js:738:37)
at async Router.execute (/workspaces/fresh-t3-app/node_modules/next/dist/server/router.js:252:36)
at async NextNodeServer.run (/workspaces/fresh-t3-app/node_modules/next/dist/server/base-server.js:381:29)
at async NextNodeServer.handleRequest (/workspaces/fresh-t3-app/node_modules/next/dist/server/base-server.js:319:20)
Agree, logs should be printed in prod too - although doesn't really work since most will deploy on Vercel and they don't persist logs (unless you're on their Enterprise plan)
For a serious app you should probably use some sort of logging service such as Axiom to keep track of your logs, so maybe we shouldn't "recommend" console-logging by putting it there?
I basically agree that errors should be logged in prod. However there are a bunch of different ways to do this, depending on deployment target, existing apps, etc. Is there something we can do that's "good enough" for a default? Personally I think by having the logger but only make it log in dev, we're making clear how do approach this for prod.
What should we do here?
- do nothing and assume that people will know how to add their own logging to prod based on the dev logger
- add some kind of default for prod, presumably just
console.error- i don't think we should remove the
if env = developmentline, as this has a nice educational function
- i don't think we should remove the
- something else?
I would recommend something like this:
onError: ({ path, error }) => {
if (env.NODE_ENV === "development") {
console.error(`❌ tRPC failed on ${path}`);
}
console.error(error);
}
- On production, this makes the behavior matches what Next.js does for API routes.
- On development, also get to see the stack trace in the console, making things easier to debug too.
most will deploy on Vercel and they don't persist logs (unless you're on their Enterprise plan)
Vercel does persist logs printed to stderr for about 1 day. So using console.error() should work.
Logging is a problem we leave to the developer and wont prescribe a best practise here as it may be interpreted as being "good enough" to just console.error your logs to stderr on Vercel which it really isn't for any production app...