@kood/claude-code 0.5.8 → 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,680 @@
|
|
|
1
|
+
# Consola
|
|
2
|
+
|
|
3
|
+
> **Version 3.x** | Elegant Console Logger for Node.js & Browser
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<context>
|
|
8
|
+
|
|
9
|
+
**Purpose:** 타입 안전하고 우아한 콘솔 로깅 라이브러리
|
|
10
|
+
|
|
11
|
+
**Key Features:**
|
|
12
|
+
- 우아한 콘솔 출력 (색상, 아이콘, 포맷팅)
|
|
13
|
+
- 로그 레벨 관리 (0-5, Silent, Verbose)
|
|
14
|
+
- 커스텀 리포터 지원
|
|
15
|
+
- 프롬프트 기능 (clack 기반)
|
|
16
|
+
- 테스트 환경 Mock 지원
|
|
17
|
+
- 타입스크립트 완벽 지원
|
|
18
|
+
- 작은 번들 크기 (`consola/basic`, `consola/browser`, `consola/core` - 80% 크기 감소)
|
|
19
|
+
|
|
20
|
+
**Bundle Size:**
|
|
21
|
+
- `consola`: ~8KB (전체 기능)
|
|
22
|
+
- `consola/basic`: ~2KB (기본 로깅)
|
|
23
|
+
- `consola/browser`: ~2KB (브라우저 전용)
|
|
24
|
+
- `consola/core`: ~1KB (최소 기능)
|
|
25
|
+
|
|
26
|
+
</context>
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
<forbidden>
|
|
31
|
+
|
|
32
|
+
| 분류 | 금지 |
|
|
33
|
+
|------|------|
|
|
34
|
+
| **로깅** | ❌ `console.log()` 직접 사용 (consola 사용) |
|
|
35
|
+
| **로그 레벨** | ❌ 프로덕션 환경에서 로그 레벨 미설정 |
|
|
36
|
+
| **에러 핸들링** | ❌ 에러를 `console.error()` 직접 출력 |
|
|
37
|
+
| **테스트** | ❌ 테스트에서 실제 콘솔 출력 (Mock 사용) |
|
|
38
|
+
|
|
39
|
+
</forbidden>
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
<required>
|
|
44
|
+
|
|
45
|
+
| 분류 | 필수 |
|
|
46
|
+
|------|------|
|
|
47
|
+
| **환경 변수** | ✅ `CONSOLA_LEVEL` 설정 (프로덕션) |
|
|
48
|
+
| **로그 레벨** | ✅ 프로덕션: 3 (log) 이하, 개발: 4 (debug) 이상 |
|
|
49
|
+
| **에러 처리** | ✅ `consola.error()` 사용 |
|
|
50
|
+
| **테스트** | ✅ `mockTypes()` 또는 `pauseLogs()` 사용 |
|
|
51
|
+
| **Next.js** | ✅ Server Action에서 `consola.info()` 사용 |
|
|
52
|
+
|
|
53
|
+
</required>
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
<installation>
|
|
58
|
+
|
|
59
|
+
## 설치
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install consola@^3.0.0
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Bundle 최적화
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// ✅ 전체 기능 (8KB)
|
|
69
|
+
import { consola } from 'consola'
|
|
70
|
+
|
|
71
|
+
// ✅ 기본 로깅 (2KB, 80% 크기 감소)
|
|
72
|
+
import { consola } from 'consola/basic'
|
|
73
|
+
|
|
74
|
+
// ✅ 브라우저 전용 (2KB)
|
|
75
|
+
import { consola } from 'consola/browser'
|
|
76
|
+
|
|
77
|
+
// ✅ 최소 기능 (1KB)
|
|
78
|
+
import { consola } from 'consola/core'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**권장사항:**
|
|
82
|
+
- 서버: `consola` (전체 기능)
|
|
83
|
+
- 클라이언트: `consola/basic` (크기 최적화)
|
|
84
|
+
- 브라우저 전용: `consola/browser`
|
|
85
|
+
|
|
86
|
+
</installation>
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
<basic_usage>
|
|
91
|
+
|
|
92
|
+
## 기본 사용법
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { consola } from 'consola'
|
|
96
|
+
|
|
97
|
+
// 기본 로그 레벨 (0-5)
|
|
98
|
+
consola.fatal('Fatal error!') // 0: 치명적 에러
|
|
99
|
+
consola.error('Error occurred!') // 1: 에러
|
|
100
|
+
consola.warn('Warning message') // 2: 경고
|
|
101
|
+
consola.log('Log message') // 3: 일반 로그 (기본값)
|
|
102
|
+
consola.info('Info message') // 4: 정보
|
|
103
|
+
consola.debug('Debug message') // 5: 디버그
|
|
104
|
+
consola.trace('Trace message') // 5: 추적
|
|
105
|
+
consola.verbose('Verbose message') // +999: 상세 로그
|
|
106
|
+
consola.silent('Silent message') // -999: 출력 안 됨
|
|
107
|
+
|
|
108
|
+
// 성공/시작/준비 메시지
|
|
109
|
+
consola.success('Task completed!') // ✅ 성공
|
|
110
|
+
consola.start('Starting task...') // ⏳ 시작
|
|
111
|
+
consola.ready('Server is ready!') // ✅ 준비 완료
|
|
112
|
+
|
|
113
|
+
// 박스 출력
|
|
114
|
+
consola.box('Important Message') // 박스로 감싸서 출력
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 로거 생성
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { createConsola } from 'consola'
|
|
121
|
+
|
|
122
|
+
// 커스텀 태그
|
|
123
|
+
const logger = createConsola({
|
|
124
|
+
level: 4, // info 레벨까지 출력
|
|
125
|
+
fancy: true, // 색상 및 아이콘 사용
|
|
126
|
+
formatOptions: {
|
|
127
|
+
date: true, // 타임스탬프 표시
|
|
128
|
+
},
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
// 태그 추가
|
|
132
|
+
const apiLogger = logger.withTag('API')
|
|
133
|
+
apiLogger.info('Request received') // [API] Request received
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## 환경 변수
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# 로그 레벨 설정
|
|
140
|
+
CONSOLA_LEVEL=3 # 0: fatal, 1: error, 2: warn, 3: log, 4: info, 5: debug/trace
|
|
141
|
+
|
|
142
|
+
# 프로덕션
|
|
143
|
+
CONSOLA_LEVEL=3 # log까지만 출력
|
|
144
|
+
|
|
145
|
+
# 개발
|
|
146
|
+
CONSOLA_LEVEL=5 # 모든 로그 출력
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
</basic_usage>
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
<log_levels>
|
|
154
|
+
|
|
155
|
+
## 로그 레벨
|
|
156
|
+
|
|
157
|
+
| 레벨 | 값 | 메서드 | 사용 |
|
|
158
|
+
|------|------|--------|------|
|
|
159
|
+
| **fatal** | 0 | `consola.fatal()` | 치명적 에러 (프로세스 종료) |
|
|
160
|
+
| **error** | 1 | `consola.error()` | 에러 발생 |
|
|
161
|
+
| **warn** | 2 | `consola.warn()` | 경고 메시지 |
|
|
162
|
+
| **log** | 3 | `consola.log()` | 일반 로그 (기본값) |
|
|
163
|
+
| **info** | 4 | `consola.info()` | 정보성 메시지 |
|
|
164
|
+
| **debug** | 5 | `consola.debug()` | 디버그 정보 |
|
|
165
|
+
| **trace** | 5 | `consola.trace()` | 추적 정보 |
|
|
166
|
+
| **verbose** | +999 | `consola.verbose()` | 상세 로그 |
|
|
167
|
+
| **silent** | -999 | `consola.silent()` | 출력 안 됨 |
|
|
168
|
+
|
|
169
|
+
### 로그 레벨 설정
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
import { consola } from 'consola'
|
|
173
|
+
|
|
174
|
+
// 레벨 설정
|
|
175
|
+
consola.level = 3 // log까지만 출력
|
|
176
|
+
consola.level = 5 // 모든 로그 출력 (debug/trace 포함)
|
|
177
|
+
|
|
178
|
+
// 환경별 설정
|
|
179
|
+
if (process.env.NODE_ENV === 'production') {
|
|
180
|
+
consola.level = 2 // warn, error, fatal만 출력
|
|
181
|
+
} else {
|
|
182
|
+
consola.level = 5 // 개발 환경: 모든 로그 출력
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 환경 변수로 제어
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# .env.production
|
|
190
|
+
CONSOLA_LEVEL=2 # warn, error, fatal
|
|
191
|
+
|
|
192
|
+
# .env.development
|
|
193
|
+
CONSOLA_LEVEL=5 # 모든 로그
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
</log_levels>
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
<custom_reporters>
|
|
201
|
+
|
|
202
|
+
## 커스텀 리포터
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { consola, createConsola, type ConsolaReporter } from 'consola'
|
|
206
|
+
|
|
207
|
+
// 파일 리포터
|
|
208
|
+
const fileReporter: ConsolaReporter = {
|
|
209
|
+
log(logObj) {
|
|
210
|
+
const message = `[${logObj.date.toISOString()}] ${logObj.type}: ${logObj.args.join(' ')}`
|
|
211
|
+
fs.appendFileSync('app.log', message + '\n')
|
|
212
|
+
},
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Sentry 리포터
|
|
216
|
+
const sentryReporter: ConsolaReporter = {
|
|
217
|
+
log(logObj) {
|
|
218
|
+
if (logObj.level <= 1) { // error, fatal
|
|
219
|
+
Sentry.captureException(new Error(logObj.args.join(' ')))
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// 리포터 추가
|
|
225
|
+
const logger = createConsola({
|
|
226
|
+
reporters: [
|
|
227
|
+
consola.options.reporters[0], // 기본 콘솔 리포터
|
|
228
|
+
fileReporter,
|
|
229
|
+
sentryReporter,
|
|
230
|
+
],
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
logger.error('This will be logged to console, file, and Sentry')
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## 프로덕션 리포터 패턴
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
import { createConsola } from 'consola'
|
|
240
|
+
|
|
241
|
+
// 환경별 리포터 설정
|
|
242
|
+
const reporters = [consola.options.reporters[0]] // 기본 콘솔
|
|
243
|
+
|
|
244
|
+
if (process.env.NODE_ENV === 'production') {
|
|
245
|
+
// 프로덕션: 파일 + 외부 로깅 서비스
|
|
246
|
+
reporters.push(fileReporter, sentryReporter)
|
|
247
|
+
} else {
|
|
248
|
+
// 개발: 콘솔만
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export const logger = createConsola({
|
|
252
|
+
level: process.env.NODE_ENV === 'production' ? 2 : 5,
|
|
253
|
+
reporters,
|
|
254
|
+
})
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
</custom_reporters>
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
<testing>
|
|
262
|
+
|
|
263
|
+
## 테스트 통합
|
|
264
|
+
|
|
265
|
+
### Mock 사용
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import { consola } from 'consola'
|
|
269
|
+
|
|
270
|
+
describe('User Service', () => {
|
|
271
|
+
beforeEach(() => {
|
|
272
|
+
// 모든 로그 Mock
|
|
273
|
+
consola.mockTypes(() => vi.fn())
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
afterEach(() => {
|
|
277
|
+
// Mock 복원
|
|
278
|
+
consola.restoreAll()
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
it('should log user creation', async () => {
|
|
282
|
+
const spy = vi.fn()
|
|
283
|
+
consola.mockTypes((type) => spy)
|
|
284
|
+
|
|
285
|
+
await createUser({ name: 'Alice' })
|
|
286
|
+
|
|
287
|
+
expect(spy).toHaveBeenCalledWith('User created:', 'Alice')
|
|
288
|
+
})
|
|
289
|
+
})
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Pause/Resume
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import { consola } from 'consola'
|
|
296
|
+
|
|
297
|
+
describe('API Tests', () => {
|
|
298
|
+
beforeAll(() => {
|
|
299
|
+
// 테스트 중 로그 일시 중지
|
|
300
|
+
consola.pauseLogs()
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
afterAll(() => {
|
|
304
|
+
// 로그 재개
|
|
305
|
+
consola.resumeLogs()
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
it('should not log during test', () => {
|
|
309
|
+
consola.log('This will not be printed')
|
|
310
|
+
})
|
|
311
|
+
})
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Vitest 통합
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
import { consola } from 'consola'
|
|
318
|
+
import { beforeEach, afterEach, vi } from 'vitest'
|
|
319
|
+
|
|
320
|
+
beforeEach(() => {
|
|
321
|
+
consola.mockTypes(() => vi.fn())
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
afterEach(() => {
|
|
325
|
+
consola.restoreAll()
|
|
326
|
+
})
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
</testing>
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
<advanced>
|
|
334
|
+
|
|
335
|
+
## 고급 기능
|
|
336
|
+
|
|
337
|
+
### Prompt (clack 기반)
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
import { consola } from 'consola'
|
|
341
|
+
|
|
342
|
+
// 텍스트 입력
|
|
343
|
+
const name = await consola.prompt('What is your name?', {
|
|
344
|
+
type: 'text',
|
|
345
|
+
default: 'User',
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
// 확인
|
|
349
|
+
const confirmed = await consola.prompt('Are you sure?', {
|
|
350
|
+
type: 'confirm',
|
|
351
|
+
initial: false,
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
// 선택
|
|
355
|
+
const framework = await consola.prompt('Choose a framework:', {
|
|
356
|
+
type: 'select',
|
|
357
|
+
options: ['React', 'Vue', 'Svelte', 'Angular'],
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
// 다중 선택
|
|
361
|
+
const features = await consola.prompt('Select features:', {
|
|
362
|
+
type: 'multiselect',
|
|
363
|
+
options: ['TypeScript', 'ESLint', 'Prettier', 'Vitest'],
|
|
364
|
+
required: true,
|
|
365
|
+
})
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Console Redirect
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
import { consola } from 'consola'
|
|
372
|
+
|
|
373
|
+
// console.log를 consola로 리다이렉트
|
|
374
|
+
consola.wrapConsole()
|
|
375
|
+
|
|
376
|
+
console.log('This uses consola now!') // consola.log()로 출력됨
|
|
377
|
+
|
|
378
|
+
// 복원
|
|
379
|
+
consola.restoreConsole()
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Pause/Resume, Mock 기능:** 자세한 내용은 `<testing>` 및 `<utilities>` 섹션을 참고하세요.
|
|
383
|
+
|
|
384
|
+
</advanced>
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
<utilities>
|
|
389
|
+
|
|
390
|
+
## 유틸리티
|
|
391
|
+
|
|
392
|
+
### withTag
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
import { consola } from 'consola'
|
|
396
|
+
|
|
397
|
+
// 태그 추가
|
|
398
|
+
const apiLogger = consola.withTag('API')
|
|
399
|
+
apiLogger.info('Request received') // [API] Request received
|
|
400
|
+
|
|
401
|
+
const dbLogger = consola.withTag('DB')
|
|
402
|
+
dbLogger.warn('Connection slow') // [DB] Connection slow
|
|
403
|
+
|
|
404
|
+
// 다중 태그
|
|
405
|
+
const authLogger = consola.withTag('API').withTag('Auth')
|
|
406
|
+
authLogger.info('User logged in') // [API] [Auth] User logged in
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### wrapConsole
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
import { consola } from 'consola'
|
|
413
|
+
|
|
414
|
+
// console.* 메서드를 consola로 래핑
|
|
415
|
+
consola.wrapConsole()
|
|
416
|
+
|
|
417
|
+
console.log('Uses consola') // consola.log()
|
|
418
|
+
console.error('Uses consola') // consola.error()
|
|
419
|
+
|
|
420
|
+
// 복원
|
|
421
|
+
consola.restoreConsole()
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### wrapStd
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
import { consola } from 'consola'
|
|
428
|
+
|
|
429
|
+
// process.stdout/stderr를 consola로 래핑
|
|
430
|
+
consola.wrapStd()
|
|
431
|
+
|
|
432
|
+
process.stdout.write('Uses consola\n') // consola.log()
|
|
433
|
+
process.stderr.write('Uses consola\n') // consola.error()
|
|
434
|
+
|
|
435
|
+
// 복원
|
|
436
|
+
consola.restoreStd()
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### wrapAll
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
import { consola } from 'consola'
|
|
443
|
+
|
|
444
|
+
// console + process.std* 모두 래핑
|
|
445
|
+
consola.wrapAll()
|
|
446
|
+
|
|
447
|
+
console.log('Uses consola')
|
|
448
|
+
process.stdout.write('Uses consola\n')
|
|
449
|
+
|
|
450
|
+
// 복원
|
|
451
|
+
consola.restoreAll()
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
</utilities>
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
<patterns>
|
|
459
|
+
|
|
460
|
+
## Next.js 패턴
|
|
461
|
+
|
|
462
|
+
### API Routes
|
|
463
|
+
|
|
464
|
+
```typescript
|
|
465
|
+
import { consola } from 'consola'
|
|
466
|
+
import type { NextApiRequest, NextApiResponse } from 'next'
|
|
467
|
+
|
|
468
|
+
// ✅ API Route 로깅
|
|
469
|
+
export default async function handler(
|
|
470
|
+
req: NextApiRequest,
|
|
471
|
+
res: NextApiResponse
|
|
472
|
+
) {
|
|
473
|
+
const logger = consola.withTag('API')
|
|
474
|
+
|
|
475
|
+
logger.info('Request:', req.method, req.url)
|
|
476
|
+
|
|
477
|
+
try {
|
|
478
|
+
const users = await prisma.user.findMany()
|
|
479
|
+
logger.success('Users fetched:', users.length)
|
|
480
|
+
res.status(200).json(users)
|
|
481
|
+
} catch (error) {
|
|
482
|
+
logger.error('Failed to fetch users:', error)
|
|
483
|
+
res.status(500).json({ error: 'Internal Server Error' })
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### Next.js - Server Actions
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
'use server'
|
|
492
|
+
|
|
493
|
+
import { consola } from 'consola'
|
|
494
|
+
|
|
495
|
+
// ✅ Server Action 로깅
|
|
496
|
+
export async function createUser(formData: FormData) {
|
|
497
|
+
const logger = consola.withTag('Action').withTag('User')
|
|
498
|
+
|
|
499
|
+
logger.info('Creating user from form data')
|
|
500
|
+
|
|
501
|
+
try {
|
|
502
|
+
const user = await prisma.user.create({
|
|
503
|
+
data: {
|
|
504
|
+
email: formData.get('email') as string,
|
|
505
|
+
name: formData.get('name') as string,
|
|
506
|
+
},
|
|
507
|
+
})
|
|
508
|
+
|
|
509
|
+
logger.success('User created:', user.id)
|
|
510
|
+
return { success: true, user }
|
|
511
|
+
} catch (error) {
|
|
512
|
+
logger.error('Failed to create user:', error)
|
|
513
|
+
return { success: false, error: 'Failed to create user' }
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### 환경별 로거 설정
|
|
519
|
+
|
|
520
|
+
```typescript
|
|
521
|
+
// lib/logger.ts
|
|
522
|
+
import { createConsola } from 'consola'
|
|
523
|
+
|
|
524
|
+
export const logger = createConsola({
|
|
525
|
+
level: process.env.NODE_ENV === 'production' ? 2 : 5, // prod: warn, dev: trace
|
|
526
|
+
fancy: process.env.NODE_ENV !== 'production', // 개발 환경에서만 색상/아이콘
|
|
527
|
+
formatOptions: {
|
|
528
|
+
date: true, // 타임스탬프
|
|
529
|
+
},
|
|
530
|
+
})
|
|
531
|
+
|
|
532
|
+
// 사용
|
|
533
|
+
import { logger } from '@/lib/logger'
|
|
534
|
+
|
|
535
|
+
logger.info('Application started')
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### 프로덕션 에러 리포터
|
|
539
|
+
|
|
540
|
+
```typescript
|
|
541
|
+
import { createConsola, type ConsolaReporter } from 'consola'
|
|
542
|
+
import * as Sentry from '@sentry/nextjs'
|
|
543
|
+
|
|
544
|
+
// Sentry 리포터
|
|
545
|
+
const sentryReporter: ConsolaReporter = {
|
|
546
|
+
log(logObj) {
|
|
547
|
+
if (logObj.level <= 1) { // error, fatal
|
|
548
|
+
Sentry.captureException(new Error(logObj.args.join(' ')), {
|
|
549
|
+
level: logObj.level === 0 ? 'fatal' : 'error',
|
|
550
|
+
tags: {
|
|
551
|
+
type: logObj.type,
|
|
552
|
+
},
|
|
553
|
+
})
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
export const logger = createConsola({
|
|
559
|
+
level: 2, // warn, error, fatal
|
|
560
|
+
reporters: [
|
|
561
|
+
consola.options.reporters[0], // 콘솔
|
|
562
|
+
sentryReporter, // Sentry
|
|
563
|
+
],
|
|
564
|
+
})
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
</patterns>
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
<dos_and_donts>
|
|
572
|
+
|
|
573
|
+
## Do's & Don'ts
|
|
574
|
+
|
|
575
|
+
### ✅ Do
|
|
576
|
+
|
|
577
|
+
| 상황 | 방법 |
|
|
578
|
+
|------|------|
|
|
579
|
+
| **로깅** | `consola.log()` 사용 |
|
|
580
|
+
| **에러** | `consola.error()` 사용 |
|
|
581
|
+
| **성공** | `consola.success()` 사용 |
|
|
582
|
+
| **태그** | `.withTag()` 사용 |
|
|
583
|
+
| **환경별** | `CONSOLA_LEVEL` 환경 변수 설정 |
|
|
584
|
+
| **테스트** | `mockTypes()` 또는 `pauseLogs()` 사용 |
|
|
585
|
+
| **프로덕션** | 로그 레벨 2 이하 (warn, error, fatal) |
|
|
586
|
+
| **개발** | 로그 레벨 5 (debug/trace 포함) |
|
|
587
|
+
|
|
588
|
+
### ❌ Don't
|
|
589
|
+
|
|
590
|
+
| 상황 | 이유 |
|
|
591
|
+
|------|------|
|
|
592
|
+
| **console.log** | ❌ 직접 사용 금지 → `consola.log()` 사용 |
|
|
593
|
+
| **프로덕션 로그** | ❌ 로그 레벨 미설정 → 불필요한 로그 출력 |
|
|
594
|
+
| **테스트 출력** | ❌ 실제 콘솔 출력 → Mock 사용 |
|
|
595
|
+
| **에러 무시** | ❌ `console.error()` 직접 사용 → `consola.error()` + 리포터 |
|
|
596
|
+
| **번들 크기** | ❌ 클라이언트에서 전체 패키지 사용 → `consola/basic` 사용 |
|
|
597
|
+
|
|
598
|
+
### 환경별 패턴
|
|
599
|
+
|
|
600
|
+
```typescript
|
|
601
|
+
// ❌ 로그 레벨 미설정
|
|
602
|
+
import { consola } from 'consola'
|
|
603
|
+
consola.debug('This will be printed in production!') // 불필요한 로그
|
|
604
|
+
|
|
605
|
+
// ✅ 환경별 로그 레벨 설정
|
|
606
|
+
import { createConsola } from 'consola'
|
|
607
|
+
|
|
608
|
+
export const logger = createConsola({
|
|
609
|
+
level: process.env.NODE_ENV === 'production' ? 2 : 5,
|
|
610
|
+
})
|
|
611
|
+
|
|
612
|
+
logger.debug('This is only printed in development')
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### 테스트 패턴
|
|
616
|
+
|
|
617
|
+
```typescript
|
|
618
|
+
// ❌ 테스트 중 콘솔 출력
|
|
619
|
+
describe('Test', () => {
|
|
620
|
+
it('should work', () => {
|
|
621
|
+
consola.log('This will clutter test output') // 출력됨
|
|
622
|
+
})
|
|
623
|
+
})
|
|
624
|
+
|
|
625
|
+
// ✅ Mock 사용
|
|
626
|
+
describe('Test', () => {
|
|
627
|
+
beforeEach(() => consola.mockTypes(() => vi.fn()))
|
|
628
|
+
afterEach(() => consola.restoreAll())
|
|
629
|
+
|
|
630
|
+
it('should work', () => {
|
|
631
|
+
consola.log('This will not clutter test output') // Mock됨
|
|
632
|
+
})
|
|
633
|
+
})
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
</dos_and_donts>
|
|
637
|
+
|
|
638
|
+
---
|
|
639
|
+
|
|
640
|
+
<quick_reference>
|
|
641
|
+
|
|
642
|
+
## Quick Reference
|
|
643
|
+
|
|
644
|
+
```typescript
|
|
645
|
+
// 설치
|
|
646
|
+
import { consola } from 'consola'
|
|
647
|
+
import { consola } from 'consola/basic' // 80% 크기 감소
|
|
648
|
+
|
|
649
|
+
// 기본 로깅
|
|
650
|
+
consola.log('Log')
|
|
651
|
+
consola.info('Info')
|
|
652
|
+
consola.warn('Warning')
|
|
653
|
+
consola.error('Error')
|
|
654
|
+
consola.success('Success')
|
|
655
|
+
|
|
656
|
+
// 태그
|
|
657
|
+
const logger = consola.withTag('API')
|
|
658
|
+
logger.info('Request') // [API] Request
|
|
659
|
+
|
|
660
|
+
// 로그 레벨
|
|
661
|
+
consola.level = 3 // log까지만 출력
|
|
662
|
+
CONSOLA_LEVEL=3 # 환경 변수
|
|
663
|
+
|
|
664
|
+
// 테스트
|
|
665
|
+
consola.mockTypes(() => vi.fn())
|
|
666
|
+
consola.pauseLogs()
|
|
667
|
+
consola.resumeLogs()
|
|
668
|
+
consola.restoreAll()
|
|
669
|
+
|
|
670
|
+
// 프롬프트
|
|
671
|
+
const name = await consola.prompt('Name?', { type: 'text' })
|
|
672
|
+
const ok = await consola.prompt('Sure?', { type: 'confirm' })
|
|
673
|
+
|
|
674
|
+
// 커스텀 리포터
|
|
675
|
+
const logger = createConsola({
|
|
676
|
+
reporters: [consola.options.reporters[0], customReporter],
|
|
677
|
+
})
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
</quick_reference>
|