Skip to content

Commit

Permalink
trpc logger example
Browse files Browse the repository at this point in the history
  • Loading branch information
c-ehrlich committed Nov 15, 2023
1 parent c01671a commit 7af84e1
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 29 deletions.
37 changes: 18 additions & 19 deletions examples/trpc/src/server/api/routers/post.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
import { z } from "zod";
import { z } from 'zod';

import { createTRPCRouter, publicProcedure } from "~/server/api/trpc";
import { createTRPCRouter, publicProcedure } from '~/server/api/trpc';

let post = {
id: 1,
name: "Hello World",
name: 'Hello World',
};

export const postRouter = createTRPCRouter({
hello: publicProcedure
.input(z.object({ text: z.string() }))
.query(({ input }) => {
return {
greeting: `Hello ${input.text}`,
};
}),
hello: publicProcedure.input(z.object({ text: z.string() })).query(({ ctx, input }) => {
ctx.log.info('Hello from the `hello` procedure', { input });
return {
greeting: `Hello ${input.text}`,
};
}),

create: publicProcedure
.input(z.object({ name: z.string().min(1) }))
.mutation(async ({ input }) => {
// simulate a slow db call
await new Promise((resolve) => setTimeout(resolve, 1000));
create: publicProcedure.input(z.object({ name: z.string().min(1) })).mutation(async ({ ctx, input }) => {
// simulate a slow db call
await new Promise((resolve) => setTimeout(resolve, 1000));

post = { id: post.id + 1, name: input.name };
return post;
}),
post = { id: post.id + 1, name: input.name };
ctx.log.info('Hello from `create` procedure.', { post });
return post;
}),

getLatest: publicProcedure.query(() => {
getLatest: publicProcedure.query((opts) => {
opts.ctx.log.info('Hello from `getLatest` procedure.', { latestPost: post });
return post;
}),
});
33 changes: 23 additions & 10 deletions examples/trpc/src/server/api/trpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
* TL;DR - This is where all the tRPC server stuff is created and plugged in. The pieces you will
* need to use are documented accordingly near the end.
*/
import { initTRPC } from "@trpc/server";
import { type NextRequest } from "next/server";
import superjson from "superjson";
import { ZodError } from "zod";
import { initTRPC } from '@trpc/server';
import superjson from 'superjson';
import { ZodError } from 'zod';
import { type NextRequest } from 'next/server';
import { axiomTRPCMiddleware, type axiomTRPCMiddlewareCtx } from 'next-axiom';

/**
* 1. CONTEXT
Expand Down Expand Up @@ -48,9 +49,18 @@ export const createInnerTRPCContext = (opts: CreateContextOptions) => {
export const createTRPCContext = (opts: { req: NextRequest }) => {
// Fetch stuff that depends on the request

return createInnerTRPCContext({
headers: opts.req.headers,
});
return {
req: opts.req,
axiomTRPCMeta: {
foo: 'bar',
random: Math.random(),
},
...createInnerTRPCContext({
headers: opts.req.headers,
}),
// optional, but gives better errors if the context
// doesn't match what the axiomTRPCMiddleware expects
} satisfies axiomTRPCMiddlewareCtx;
};

/**
Expand All @@ -68,8 +78,7 @@ const t = initTRPC.context<typeof createTRPCContext>().create({
...shape,
data: {
...shape.data,
zodError:
error.cause instanceof ZodError ? error.cause.flatten() : null,
zodError: error.cause instanceof ZodError ? error.cause.flatten() : null,
},
};
},
Expand All @@ -96,4 +105,8 @@ export const createTRPCRouter = t.router;
* guarantee that a user querying is authorized, but you can still access user session data if they
* are logged in.
*/
export const publicProcedure = t.procedure;

// we probably want all procedures to log, so we attach the axiomMiddleware to a base procedure
const baseProcedure = t.procedure.use(axiomTRPCMiddleware);

export const publicProcedure = baseProcedure;
17 changes: 17 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"typescript": "^5.1.6"
},
"dependencies": {
"@trpc/server": "^10.43.3",
"whatwg-fetch": "^3.6.2"
}
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './config';
export { withAxiom, type AxiomRequest, withAxiomNextConfig, withAxiomRouteHandler } from './withAxiom';
export * from './webVitals';
export { useLogger } from './hooks';
export { axiomTRPCMiddleware, type axiomTRPCMiddlewareCtx } from './trpc';
52 changes: 52 additions & 0 deletions src/trpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { experimental_standaloneMiddleware } from '@trpc/server';
import { Logger, type RequestReport } from './logger';
import { type NextRequest } from 'next/server';

export type axiomTRPCMiddlewareCtx = {
/**
* TODO:
* I think it's probably better to pass req at the root instead of axiomTRPCMeta
* so that it can also be used in other places instead of possibly needing to be passed twice
*/
req: Request | NextRequest;
/**
* TODO:
* figure out the best name for this - it's anything you want to stick on all logs
* that are sent throughout the duration of this procedure.
*/
axiomTRPCMeta: Record<string, unknown>;
};

export const axiomTRPCMiddleware = experimental_standaloneMiddleware<{
ctx: axiomTRPCMiddlewareCtx;
}>().create((opts) => {
const { req } = opts.ctx;

let region = '';
if ('geo' in req) {
region = req.geo?.region ?? '';
}

const report: RequestReport = {
startTime: new Date().getTime(),
path: req.url,
method: req.method,
host: req.headers.get('host'),
userAgent: req.headers.get('user-agent'),
scheme: 'https',
ip: req.headers.get('x-forwarded-for'),
region,
};

const log = new Logger({
args: {
input: opts.rawInput, // TODO: put something if nullish?
axiomTRPCMeta: opts.ctx.axiomTRPCMeta,
},
req: report,
});

return opts.next({
ctx: { log },
});
});

0 comments on commit 7af84e1

Please sign in to comment.