Skip to content

Commit 293723a

Browse files
committed
feat: enhance logging middleware to include structured JSON output and error tracking in PostHog for better monitoring
1 parent 8cd27b3 commit 293723a

File tree

1 file changed

+81
-5
lines changed

1 file changed

+81
-5
lines changed

trpc/init.ts

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,36 +48,105 @@ export const createCallerFactory = t.createCallerFactory;
4848

4949
/**
5050
* Middleware to log the start, end, and duration of a procedure.
51+
* All logs are structured JSON for better parsing by log aggregators.
52+
* Errors are tracked in PostHog for centralized monitoring.
5153
* @param path - The path of the procedure
5254
* @param type - The type of the procedure
55+
* @param input - The input to the procedure
5356
* @param next - The next middleware
5457
* @returns The result of the next middleware
5558
*/
56-
const withLogging = t.middleware(async ({ path, type, next }) => {
59+
const withLogging = t.middleware(async ({ path, type, input, next }) => {
5760
const start = performance.now();
58-
console.debug(`[trpc] start ${path} (${type})`);
61+
62+
// Sample input for debugging (only log safe fields, avoid PII)
63+
const inputSample =
64+
input && typeof input === "object"
65+
? Object.keys(input).reduce(
66+
(acc, key) => {
67+
// Log only safe fields, truncate long values
68+
if (
69+
key === "domain" ||
70+
key === "type" ||
71+
key === "types" ||
72+
key === "limit"
73+
) {
74+
const value = (input as Record<string, unknown>)[key];
75+
acc[key] = String(value).slice(0, 100);
76+
}
77+
return acc;
78+
},
79+
{} as Record<string, string>,
80+
)
81+
: undefined;
82+
83+
console.debug(
84+
JSON.stringify({
85+
level: "debug",
86+
message: "[trpc] start",
87+
path,
88+
type,
89+
input: inputSample,
90+
timestamp: new Date().toISOString(),
91+
}),
92+
);
93+
5994
try {
6095
const result = await next();
6196
const durationMs = Math.round(performance.now() - start);
62-
console.info(`[trpc] ok ${path} (${type}) ${durationMs}ms`);
97+
98+
console.info(
99+
JSON.stringify({
100+
level: "info",
101+
message: "[trpc] ok",
102+
path,
103+
type,
104+
durationMs,
105+
timestamp: new Date().toISOString(),
106+
}),
107+
);
108+
109+
// Track slow requests (>5s threshold) in PostHog
110+
if (durationMs > 5000) {
111+
const { analytics } = await import("@/lib/analytics/server");
112+
analytics.track("trpc_slow_request", {
113+
path,
114+
type,
115+
durationMs,
116+
});
117+
}
118+
63119
return result;
64120
} catch (err) {
65121
const durationMs = Math.round(performance.now() - start);
66122
const error = err instanceof Error ? err : new Error(String(err));
123+
67124
console.error(
68125
JSON.stringify({
69126
level: "error",
70-
message: `[trpc] error ${path} (${type})`,
127+
message: "[trpc] error",
71128
path,
72129
type,
73130
durationMs,
131+
timestamp: new Date().toISOString(),
74132
error: {
75133
message: error.message,
134+
name: error.name,
76135
stack: error.stack,
77136
cause: error.cause,
78137
},
79138
}),
80139
);
140+
141+
// Track exceptions in PostHog for centralized monitoring
142+
const { analytics } = await import("@/lib/analytics/server");
143+
analytics.trackException(error, {
144+
path,
145+
type,
146+
durationMs,
147+
source: "trpc",
148+
});
149+
81150
throw err;
82151
}
83152
});
@@ -97,7 +166,14 @@ const withDomainAccessUpdate = t.middleware(async ({ input, next }) => {
97166
) {
98167
const registrable = toRegistrableDomain(input.domain);
99168
if (registrable) {
100-
console.debug(`[trpc] recording access for domain: ${registrable}`);
169+
console.debug(
170+
JSON.stringify({
171+
level: "debug",
172+
message: "[trpc] recording access for domain",
173+
domain: registrable,
174+
timestamp: new Date().toISOString(),
175+
}),
176+
);
101177
after(() => updateLastAccessed(registrable));
102178
}
103179
}

0 commit comments

Comments
 (0)