Ghost

struxadotcloud/struxa

public
Fork0
CodeIssues0Pull requests0
1branch
struxa.claudeskillsreview-logging-patternsreferencescode-review.md
initial commitd4cb9e15 months ago309 lines · 8.2 KB
1# Code Review Checklist
2
3Use this checklist when reviewing code for logging best practices and evlog adoption.
4
5## Quick Scan
6
7Run through these checks first to identify improvement opportunities:
8
9### 1. Console Statement Audit
10
11Search for these patterns:
12
13```typescript
14// ❌ Patterns to find and transform
15console.log(...)
16console.error(...)
17console.warn(...)
18console.info(...)
19console.debug(...)
20```
21
22**Questions to ask:**
23
24- Are there multiple console statements in one function?
25- Are they logging request/response data?
26- Could they be consolidated into a wide event?
27
28### 2. Error Pattern Audit
29
30Search for these patterns:
31
32```typescript
33// ❌ Generic errors
34throw new Error('
35throw Error('...')
36
37// ❌ Re-throwing without context
38catch (error) {
39 throw error
40}
41
42// ❌ Logging and throwing
43catch (error) {
44 console.error(error
45 throw error
46}
47```
48
49**Questions to ask:**
50
51- Does the error message explain what happened?
52- Is there a `why` explaining the root cause?
53- Is there a `fix` suggesting a solution?
54- Is the original error preserved as `cause`?
55
56### 3. Request Handler Audit
57
58For each API route/handler, check:
59
60```typescript
61// ❌ Missing request context
62export default defineEventHandler(async
63 // No logging at all, or scattered console.logs
64});
65```
66
67**Questions to ask:**
68
69- Is there a request-scoped logger?
70- Is context accumulated throughout the request?
71- Is there a single emit at the end?
72
73## Detailed Review
74
75### Console.log Transformations
76
77#### Single Debug Log
78
79```typescript
80// ❌ Before
81console.log("Processing user:"
82
83// ✅ After - if part of a larger operation
84log.set({ user
85
86// ✅ After - if standalone debug
87log.debug("user"
88```
89
90#### Multiple Related Logs
91
92```typescript
93// ❌ Before
94console.log("Starting checkout"
95console.log("User:"
96console.log("Cart items:"
97console.log("Total:"
98
99// ✅ After
100log.info({
101 action: "checkout",
102 user: { id: user
103 cart: { items: cart
104});
105```
106
107#### Request Lifecycle Logs
108
109```typescript
110// server/api/process.post.ts
111
112// ❌ Before
113export default defineEventHandler(async
114 console.log("Request started
115 const user =
116 console.log("User loaded
117 const result =
118 console.log("Processing complete
119 return result;
120});
121
122// ✅ After (Nuxt - auto-imported, no import needed)
123// For Nitro v3: import { useLogger } from 'evlog/nitro/v3'
124// For Nitro v2: import { useLogger } from 'evlog/nitro'
125
126export default defineEventHandler(async
127 const log =
128
129 const user =
130 log.set({
131
132 const result =
133 log.set({
134
135 return result;
136 // emit() called automatically
137});
138```
139
140### Error Transformations
141
142#### Generic Error
143
144```typescript
145// ❌ Before
146throw new Error("
147
148// ✅ After
149throw createError({
150 message: "Failed to create user",
151 why: "Email address already registered",
152 fix: "Use a different email or log in to existing account",
153 link: "https://your-app.com/docs/registration",
154});
155```
156
157#### Wrapped Error Without Context
158
159```typescript
160// ❌ Before
161try {
162 await externalApi.call
163} catch (error)
164 throw new Error(
165}
166
167// ✅ After
168try {
169 await externalApi.call
170} catch (error)
171 throw createError({
172 message: "External API call failed",
173 why: `API returned: ${error
174 fix: "Check API credentials and try again",
175 link: "https://api-docs.example.com/errors",
176 cause: error,
177 });
178}
179```
180
181#### Log-and-Throw Anti-pattern
182
183```typescript
184// ❌ Before
185try {
186 await riskyOperation();
187} catch (error)
188 console.error("Operation failed:
189 throw error;
190}
191
192// ✅ After
193try {
194 await riskyOperation();
195} catch (error)
196 log.error(error
197 throw createError({
198 message: "Operation failed",
199 why: error.message
200 fix: "Check input and retry",
201 cause: error,
202 });
203}
204```
205
206### Request Handler Transformations
207
208#### No Logging
209
210```typescript
211// server/api/orders.post.ts
212
213// ❌ Before
214export default defineEventHandler(async
215 const body =
216 const result =
217 return result;
218});
219
220// ✅ After (Nuxt - auto-imported, no import needed)
221// For Nitro v3: import { useLogger } from 'evlog/nitro/v3'
222// For Nitro v2: import { useLogger } from 'evlog/nitro'
223import { createError }
224
225export default defineEventHandler(async
226 const log =
227
228 const body =
229 log.set({
230
231 try {
232 const result =
233 log.set({
234 return result;
235 } catch (error)
236 log.error(error
237 throw createError({
238 message: "Order processing failed",
239 why: error.message
240 fix: "Check the order data and try again",
241 });
242 }
243 // emit() called automatically
244});
245```
246
247## Review Checklist Summary
248
249### Logging
250
251- [ ] No raw `console.log` statements in production code
252- [ ] Request handlers use `useLogger(event)` (Nuxt/Nitro) or `createRequestLogger()` (standalone)
253- [ ] Context is accumulated with `log.set()` throughout the request
254- [ ] `emit()` is automatic with `useLogger()`, manual with
255- [ ] Wide events include: user, business context, outcome
256
257### Errors
258
259- [ ] All errors use `createError()` instead of `new Error()` (import from
260- [ ] Every error has a clear `message` and appropriate `status` code
261- [ ] Complex errors include `why` explaining root cause
262- [ ] Fixable errors include `fix` with actionable steps
263- [ ] Documented errors include `link` to docs
264- [ ] Wrapped errors preserve `cause`
265- [ ] Support-only or sensitive diagnostics use `internal`, not `message` /
266
267### Frontend Error Handling
268
269- [ ] API errors are caught and displayed with full context (message, why, fix)
270- [ ] Toasts or error components use the structured data from `error.data.data`
271- [ ] Links to documentation are actionable (buttons/links in toasts)
272
273### Context
274
275- [ ] User context includes: id, plan/subscription, relevant business data
276- [ ] Request context includes: method, path, requestId
277- [ ] Business context is domain-specific and useful for debugging
278- [ ] No sensitive data in logs (passwords, tokens, full card numbers)
279
280## Anti-Pattern Summary
281
282| Anti-Pattern | Fix |
283| -------------------------------------- | --------------------------------------------------------------------------- |
284| Multiple `console.log` in one function | Single wide event with `useLogger(event).set()
285| `throw new Error('...')` | `throw createError({ message, status, why, fix })
286| `console.error(e); throw e` | `log.error(e); throw createError(...)
287| No logging in request handlers | Add `useLogger(event)` (Nuxt/Nitro) or `createRequestLogger()
288| Flat log data | Grouped objects: `{ user: {...}, cart: {...} }` |
289| Abbreviated field names | Descriptive names: `userId` not `uid
290
291## Suggested Review Comments
292
293Use these when leaving review feedback:
294
295### Console.log Found
296
297> Consider using evlog's wide event pattern here. Instead of multiple console.log statements, use `useLogger(event)
298
299### Generic Error
300
301> This error would benefit from evlog's structured error pattern. Consider using `import { createError } from 'evlog'
302
303### Missing Request Context
304
305> This handler would benefit from request-scoped logging. Add `useLogger(event)
306
307### Good Logging (Positive Feedback)
308
309> Nice use of wide events here! The context is well-structured and will be very useful for debugging.
...
'
)
)
(
event
)
=>
{
,
userId
)
;
:
{
id
:
userId
}
}
)
;
,
`
Processing user
${
userId
}
`
)
;
)
;
,
user
.
id
)
;
,
cart
.
items
.
length
)
;
,
cart
.
total
)
;
.
id
}
,
.
items
.
length
,
total
:
cart
.
total
}
,
(
event
)
=>
{
"
)
;
await
getUser
(
event
)
;
"
)
;
await
processData
(
user
)
;
"
)
;
(
event
)
=>
{
useLogger
(
event
)
;
await
getUser
(
event
)
;
user
:
{
id
:
user
.
id
}
}
)
;
await
processData
(
user
)
;
result
:
{
id
:
result
.
id
}
}
)
;
Failed to create user
"
)
;
()
;
{
"
API call failed
"
)
;
()
;
{
.
message
}
`
,
{
"
,
error
)
;
{
,
{
step
:
"
riskyOperation
"
}
)
;
,
(
event
)
=>
{
await
readBody
(
event
)
;
await
processOrder
(
body
)
;
from
"
evlog
"
;
(
event
)
=>
{
useLogger
(
event
)
;
await
readBody
(
event
)
;
order
:
{
items
:
body
.
items
?.
length
}
}
)
;
await
processOrder
(
body
)
;
result
:
{
orderId
:
result
.
id
,
status
:
result
.
status
}
}
)
;
{
,
{
step
:
"
processOrder
"
}
)
;
,
`
createRequestLogger()
`
`
evlog
`
)
`
why
`
/
`
fix
`
`
|
`
|
`
|
`
(standalone)
|
`
|
`
to accumulate context and emit a single comprehensive event.
`
and
`
createError({ message, status, why, fix })
`
to provide more debugging context.
`
at the start to capture context throughout the request lifecycle.