yodogawa 1.0.0

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.
Files changed (61) hide show
  1. package/.windsurf/templates/documentation-rules.md +143 -0
  2. package/.windsurf/templates/project/01-requirements/01-system-overview.md +49 -0
  3. package/.windsurf/templates/project/01-requirements/02-features-implemented.md +73 -0
  4. package/.windsurf/templates/project/01-requirements/03-features-planned.md +75 -0
  5. package/.windsurf/templates/project/01-requirements/04-non-functional-requirements.md +115 -0
  6. package/.windsurf/templates/project/01-requirements/05-user-stories.md +124 -0
  7. package/.windsurf/templates/project/02-behavior/01-scenarios.md +406 -0
  8. package/.windsurf/templates/project/03-domain/01-domain-model.md +338 -0
  9. package/.windsurf/templates/project/03-domain/02-ubiquitous-language.md +153 -0
  10. package/.windsurf/templates/project/04-design/01-tech-stack.md +360 -0
  11. package/.windsurf/templates/project/04-design/02-repository-structure.md +390 -0
  12. package/.windsurf/templates/project/04-design/03-screen-design.md +586 -0
  13. package/.windsurf/templates/project/04-design/04-data-model.md +211 -0
  14. package/.windsurf/templates/project/04-design/05-api-spec.md +221 -0
  15. package/.windsurf/templates/project/04-design/06-architecture.md +183 -0
  16. package/.windsurf/templates/project/04-design/07-infrastructure.md +180 -0
  17. package/.windsurf/templates/tasks/task-template/a-definition.md +143 -0
  18. package/.windsurf/templates/tasks/task-template/b-research.md +185 -0
  19. package/.windsurf/templates/tasks/task-template/c-implementation.md +197 -0
  20. package/.windsurf/workflows/a-001-SetupDocStructure.md +165 -0
  21. package/.windsurf/workflows/a-002-InitializeProject.md +229 -0
  22. package/.windsurf/workflows/a-003-CreateScenarios.md +130 -0
  23. package/.windsurf/workflows/a-004-DefineDomainModel.md +133 -0
  24. package/.windsurf/workflows/a-005-CreateDomainDiagram.md +114 -0
  25. package/.windsurf/workflows/a-006-ReviewRequirementsDomain.md +132 -0
  26. package/.windsurf/workflows/a-007-DefineTechStack.md +121 -0
  27. package/.windsurf/workflows/a-008-DefineRepositoryStructure.md +118 -0
  28. package/.windsurf/workflows/a-009-DefineScreenDesign.md +121 -0
  29. package/.windsurf/workflows/a-010-DefineDataModel.md +125 -0
  30. package/.windsurf/workflows/a-011-DefineAPISpec.md +123 -0
  31. package/.windsurf/workflows/a-012-DefineArchitecture.md +119 -0
  32. package/.windsurf/workflows/a-013-DefineInfrastructure.md +120 -0
  33. package/.windsurf/workflows/a-014-ReviewDesign.md +122 -0
  34. package/.windsurf/workflows/b-001-CreateTaskDirectory.md +71 -0
  35. package/.windsurf/workflows/b-002-CreateTaskDefinition.md +165 -0
  36. package/.windsurf/workflows/b-003-CreateTaskResearch.md +412 -0
  37. package/.windsurf/workflows/b-004-CreateTaskImplementation.md +97 -0
  38. package/.windsurf/workflows/b-005-ReviewTask.md +312 -0
  39. package/.windsurf/workflows/c-001-ImplementTask.md +493 -0
  40. package/.windsurf/workflows/c-002-UpdateDocumentation.md +797 -0
  41. package/.windsurf/workflows/x-Accessibility-Check.md +469 -0
  42. package/.windsurf/workflows/x-Bundle-Optimize.md +386 -0
  43. package/.windsurf/workflows/x-CI-FixFailure.md +636 -0
  44. package/.windsurf/workflows/x-CI-Setup.md +641 -0
  45. package/.windsurf/workflows/x-Code-Refactor.md +71 -0
  46. package/.windsurf/workflows/x-Code-ResearchAndReview.md +78 -0
  47. package/.windsurf/workflows/x-Component-Create.md +359 -0
  48. package/.windsurf/workflows/x-Context-CatchUp.md +63 -0
  49. package/.windsurf/workflows/x-Database-Seed.md +300 -0
  50. package/.windsurf/workflows/x-Dependencies-Update.md +315 -0
  51. package/.windsurf/workflows/x-DevEnvironment-Setup.md +437 -0
  52. package/.windsurf/workflows/x-Logging-Add.md +682 -0
  53. package/.windsurf/workflows/x-Migration-Create.md +354 -0
  54. package/.windsurf/workflows/x-Problem-RootCauseAnalysis.md +65 -0
  55. package/.windsurf/workflows/x-Repository-Push.md +375 -0
  56. package/.windsurf/workflows/x-Repository-PushToGithub.md +72 -0
  57. package/.windsurf/workflows/x-Requirements-Clarify.md +61 -0
  58. package/.windsurf/workflows/z-CreateWorkflow.md +77 -0
  59. package/README.md +280 -0
  60. package/bin/cli.js +74 -0
  61. package/package.json +28 -0
@@ -0,0 +1,682 @@
1
+ ---
2
+ description: 構造化ログを実装し、本番環境での問題調査とモニタリングを効率化するワークフロー
3
+ auto_execution_mode: 1
4
+ ---
5
+
6
+ # Logging-Add (x-Logging-Add)
7
+
8
+ ## 目的
9
+
10
+ - アプリケーションに構造化ログを実装し、本番環境での問題調査を効率化する。
11
+ - ログレベル(DEBUG, INFO, WARN, ERROR)を適切に使い分ける。
12
+ - 機密情報(パスワード、トークン、個人情報)をログに出力しない。
13
+ - ログ集約サービス(CloudWatch, Datadog, Sentry)との統合を実現する。
14
+ - リクエスト ID によるトレーサビリティを確保する。
15
+
16
+ ## 前提
17
+
18
+ - アプリケーションが動作している(Node.js, Python, Ruby など)。
19
+ - ログライブラリが利用可能(Winston, Pino, Python logging, など)。
20
+ - ログ出力先が決まっている(ファイル、標準出力、ログ集約サービス)。
21
+ - Git リポジトリが初期化されている。
22
+
23
+ ## 手順
24
+
25
+ ### 1. ログ戦略の決定
26
+
27
+ **ログフォーマットの選択**:
28
+ - **構造化ログ(JSON)**: 推奨。ログ集約サービスで検索・分析しやすい
29
+ - **テキストログ**: シンプルだが検索・分析が困難
30
+ - **ハイブリッド**: 開発環境では可読性優先、本番環境では JSON
31
+
32
+ **ログレベルの設計**:
33
+ - **ERROR**: エラー発生時(例外、失敗)
34
+ - **WARN**: 警告(非推奨 API 使用、リトライ)
35
+ - **INFO**: 重要なイベント(ユーザーログイン、支払い完了)
36
+ - **DEBUG**: デバッグ情報(SQL クエリ、API レスポンス)
37
+ - **TRACE**: 詳細なトレース(関数呼び出し)
38
+
39
+ **ログ出力先の決定**:
40
+ - **標準出力**: Docker/Kubernetes 環境推奨
41
+ - **ファイル**: ローテーション設定が必要
42
+ - **ログ集約サービス**: CloudWatch, Datadog, Sentry, Loggly
43
+
44
+ ### 2. ログライブラリのインストール
45
+
46
+ **Node.js**:
47
+ ```bash
48
+ # Winston (人気、多機能)
49
+ npm install winston
50
+
51
+ # Pino (高速、軽量)
52
+ npm install pino
53
+
54
+ # Morgan (Express 用 HTTP ログ)
55
+ npm install morgan
56
+ ```
57
+
58
+ **Python**:
59
+ ```bash
60
+ # 標準ライブラリの logging を使用
61
+ # または
62
+ pip install structlog # 構造化ログ
63
+ pip install python-json-logger # JSON フォーマット
64
+ ```
65
+
66
+ **Ruby (Rails)**:
67
+ ```bash
68
+ # 標準の Logger を使用
69
+ # または
70
+ gem install lograge # Rails のログを構造化
71
+ ```
72
+
73
+ ### 3. ロガーの設定
74
+
75
+ #### 3.1. Node.js + Winston
76
+
77
+ **logger.ts**:
78
+ ```typescript
79
+ import winston from 'winston';
80
+
81
+ const isProduction = process.env.NODE_ENV === 'production';
82
+
83
+ const logger = winston.createLogger({
84
+ level: process.env.LOG_LEVEL || (isProduction ? 'info' : 'debug'),
85
+ format: winston.format.combine(
86
+ winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
87
+ winston.format.errors({ stack: true }),
88
+ winston.format.metadata(),
89
+ isProduction
90
+ ? winston.format.json() // 本番: JSON
91
+ : winston.format.combine( // 開発: 可読性優先
92
+ winston.format.colorize(),
93
+ winston.format.printf(({ level, message, timestamp, ...meta }) => {
94
+ return `${timestamp} [${level}]: ${message} ${Object.keys(meta).length ? JSON.stringify(meta, null, 2) : ''}`;
95
+ })
96
+ )
97
+ ),
98
+ transports: [
99
+ new winston.transports.Console(),
100
+ // ファイル出力(オプション)
101
+ ...(isProduction ? [
102
+ new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
103
+ new winston.transports.File({ filename: 'logs/combined.log' }),
104
+ ] : []),
105
+ ],
106
+ });
107
+
108
+ export default logger;
109
+ ```
110
+
111
+ #### 3.2. Node.js + Pino
112
+
113
+ **logger.ts**:
114
+ ```typescript
115
+ import pino from 'pino';
116
+
117
+ const isProduction = process.env.NODE_ENV === 'production';
118
+
119
+ const logger = pino({
120
+ level: process.env.LOG_LEVEL || (isProduction ? 'info' : 'debug'),
121
+ transport: !isProduction ? {
122
+ target: 'pino-pretty',
123
+ options: {
124
+ colorize: true,
125
+ translateTime: 'SYS:standard',
126
+ ignore: 'pid,hostname',
127
+ },
128
+ } : undefined,
129
+ });
130
+
131
+ export default logger;
132
+ ```
133
+
134
+ #### 3.3. Python + structlog
135
+
136
+ **logger.py**:
137
+ ```python
138
+ import structlog
139
+ import logging
140
+ import sys
141
+
142
+ def setup_logging():
143
+ logging.basicConfig(
144
+ format="%(message)s",
145
+ stream=sys.stdout,
146
+ level=logging.INFO,
147
+ )
148
+
149
+ structlog.configure(
150
+ processors=[
151
+ structlog.stdlib.filter_by_level,
152
+ structlog.stdlib.add_logger_name,
153
+ structlog.stdlib.add_log_level,
154
+ structlog.stdlib.PositionalArgumentsFormatter(),
155
+ structlog.processors.TimeStamper(fmt="iso"),
156
+ structlog.processors.StackInfoRenderer(),
157
+ structlog.processors.format_exc_info,
158
+ structlog.processors.UnicodeDecoder(),
159
+ structlog.processors.JSONRenderer() # JSON 出力
160
+ ],
161
+ context_class=dict,
162
+ logger_factory=structlog.stdlib.LoggerFactory(),
163
+ cache_logger_on_first_use=True,
164
+ )
165
+
166
+ logger = structlog.get_logger()
167
+ ```
168
+
169
+ ### 4. リクエスト ID の追加
170
+
171
+ リクエスト ID を各ログエントリに追加することで、分散システムでのトレーサビリティを確保します。
172
+
173
+ #### 4.1. Web フレームワークのミドルウェア実装
174
+
175
+ **Express (Node.js) の例**:
176
+
177
+ **requestLogger.ts**:
178
+ ```typescript
179
+ import { Request, Response, NextFunction } from 'express';
180
+ import { v4 as uuidv4 } from 'uuid';
181
+ import logger from './logger';
182
+
183
+ export function requestLoggerMiddleware(req: Request, res: Response, next: NextFunction) {
184
+ const requestId = req.headers['x-request-id'] as string || uuidv4();
185
+ req.requestId = requestId;
186
+ res.setHeader('X-Request-ID', requestId);
187
+
188
+ // リクエストログ
189
+ logger.info('Incoming request', {
190
+ requestId,
191
+ method: req.method,
192
+ url: req.url,
193
+ userAgent: req.headers['user-agent'],
194
+ ip: req.ip,
195
+ });
196
+
197
+ const startTime = Date.now();
198
+
199
+ res.on('finish', () => {
200
+ const duration = Date.now() - startTime;
201
+ logger.info('Request completed', {
202
+ requestId,
203
+ method: req.method,
204
+ url: req.url,
205
+ statusCode: res.statusCode,
206
+ duration: `${duration}ms`,
207
+ });
208
+ });
209
+
210
+ next();
211
+ }
212
+ ```
213
+
214
+ **app.ts**:
215
+ ```typescript
216
+ import express from 'express';
217
+ import { requestLoggerMiddleware } from './middleware/requestLogger';
218
+
219
+ const app = express();
220
+
221
+ app.use(requestLoggerMiddleware);
222
+ ```
223
+
224
+ #### 4.2. Django ミドルウェア
225
+
226
+ **middleware.py**:
227
+ ```python
228
+ import uuid
229
+ import time
230
+ import structlog
231
+
232
+ logger = structlog.get_logger()
233
+
234
+ class RequestLoggingMiddleware:
235
+ def __init__(self, get_response):
236
+ self.get_response = get_response
237
+
238
+ def __call__(self, request):
239
+ request_id = request.headers.get('X-Request-ID', str(uuid.uuid4()))
240
+ request.request_id = request_id
241
+
242
+ logger.info(
243
+ "incoming_request",
244
+ request_id=request_id,
245
+ method=request.method,
246
+ path=request.path,
247
+ user_agent=request.META.get('HTTP_USER_AGENT'),
248
+ ip=request.META.get('REMOTE_ADDR'),
249
+ )
250
+
251
+ start_time = time.time()
252
+ response = self.get_response(request)
253
+ duration = (time.time() - start_time) * 1000
254
+
255
+ logger.info(
256
+ "request_completed",
257
+ request_id=request_id,
258
+ method=request.method,
259
+ path=request.path,
260
+ status_code=response.status_code,
261
+ duration_ms=round(duration, 2),
262
+ )
263
+
264
+ response['X-Request-ID'] = request_id
265
+ return response
266
+ ```
267
+
268
+ **settings.py**:
269
+ ```python
270
+ MIDDLEWARE = [
271
+ 'myapp.middleware.RequestLoggingMiddleware',
272
+ # ...
273
+ ]
274
+ ```
275
+
276
+ ### 5. ログの追加
277
+
278
+ #### 5.1. エラーログ
279
+
280
+ **Node.js**:
281
+ ```typescript
282
+ import logger from './logger';
283
+
284
+ try {
285
+ // 処理
286
+ } catch (error) {
287
+ logger.error('Failed to process payment', {
288
+ error: error.message,
289
+ stack: error.stack,
290
+ userId: user.id,
291
+ orderId: order.id,
292
+ });
293
+ throw error;
294
+ }
295
+ ```
296
+
297
+ **Python**:
298
+ ```python
299
+ from logger import logger
300
+
301
+ try:
302
+ # 処理
303
+ except Exception as e:
304
+ logger.error(
305
+ "failed_to_process_payment",
306
+ error=str(e),
307
+ user_id=user.id,
308
+ order_id=order.id,
309
+ exc_info=True, # スタックトレースを含める
310
+ )
311
+ raise
312
+ ```
313
+
314
+ #### 5.2. 情報ログ
315
+
316
+ **Node.js**:
317
+ ```typescript
318
+ logger.info('User logged in', {
319
+ userId: user.id,
320
+ email: user.email,
321
+ loginMethod: 'password',
322
+ });
323
+
324
+ logger.info('Payment completed', {
325
+ orderId: order.id,
326
+ amount: order.amount,
327
+ currency: order.currency,
328
+ });
329
+ ```
330
+
331
+ **Python**:
332
+ ```python
333
+ logger.info(
334
+ "user_logged_in",
335
+ user_id=user.id,
336
+ email=user.email,
337
+ login_method="password",
338
+ )
339
+
340
+ logger.info(
341
+ "payment_completed",
342
+ order_id=order.id,
343
+ amount=order.amount,
344
+ currency=order.currency,
345
+ )
346
+ ```
347
+
348
+ #### 5.3. デバッグログ
349
+
350
+ **Node.js**:
351
+ ```typescript
352
+ logger.debug('Database query executed', {
353
+ query: 'SELECT * FROM users WHERE id = ?',
354
+ params: [userId],
355
+ duration: '12ms',
356
+ });
357
+
358
+ logger.debug('API response', {
359
+ endpoint: '/api/users',
360
+ statusCode: 200,
361
+ responseTime: '45ms',
362
+ });
363
+ ```
364
+
365
+ ### 6. 機密情報の除外
366
+
367
+ ログに機密情報が含まれないよう、適切なマスキング処理を実装します。
368
+
369
+ **除外すべき情報**:
370
+ - パスワード
371
+ - API キー / トークン
372
+ - クレジットカード番号
373
+ - 社会保障番号
374
+ - 個人情報(住所、電話番号)
375
+
376
+ **logger.ts(フィルター追加)**:
377
+ ```typescript
378
+ import winston from 'winston';
379
+
380
+ const sensitiveKeys = ['password', 'token', 'apiKey', 'creditCard', 'ssn'];
381
+
382
+ const maskSensitiveData = winston.format((info) => {
383
+ const maskValue = (obj: any) => {
384
+ if (typeof obj !== 'object' || obj === null) return obj;
385
+
386
+ for (const key in obj) {
387
+ if (sensitiveKeys.some(sk => key.toLowerCase().includes(sk.toLowerCase()))) {
388
+ obj[key] = '***REDACTED***';
389
+ } else if (typeof obj[key] === 'object') {
390
+ maskValue(obj[key]);
391
+ }
392
+ }
393
+ return obj;
394
+ };
395
+
396
+ return maskValue(info);
397
+ });
398
+
399
+ const logger = winston.createLogger({
400
+ format: winston.format.combine(
401
+ maskSensitiveData(),
402
+ winston.format.timestamp(),
403
+ winston.format.json()
404
+ ),
405
+ // ...
406
+ });
407
+ ```
408
+
409
+ **使用例**:
410
+ ```typescript
411
+ logger.info('User registration', {
412
+ email: 'user@example.com',
413
+ password: 'secret123', // ***REDACTED*** として出力される
414
+ });
415
+ ```
416
+
417
+ ### 7. ログローテーション
418
+
419
+ ログファイルが肥大化しないよう、ローテーション設定を行います。
420
+
421
+ **主要なログライブラリでのローテーション設定例**:
422
+
423
+ **Winston + daily-rotate-file (Node.js)**:
424
+ ```bash
425
+ npm install winston-daily-rotate-file
426
+ ```
427
+
428
+ ```typescript
429
+ import winston from 'winston';
430
+ import DailyRotateFile from 'winston-daily-rotate-file';
431
+
432
+ const logger = winston.createLogger({
433
+ transports: [
434
+ new DailyRotateFile({
435
+ filename: 'logs/application-%DATE%.log',
436
+ datePattern: 'YYYY-MM-DD',
437
+ maxSize: '20m',
438
+ maxFiles: '14d', // 14日間保持
439
+ }),
440
+ ],
441
+ });
442
+ ```
443
+
444
+ **Linux logrotate** (`/etc/logrotate.d/myapp`):
445
+ ```
446
+ /var/log/myapp/*.log {
447
+ daily
448
+ rotate 14
449
+ compress
450
+ delaycompress
451
+ missingok
452
+ notifempty
453
+ create 0640 www-data www-data
454
+ }
455
+ ```
456
+
457
+ ### 8. ログ集約サービスとの統合
458
+
459
+ 本番環境では、ログ集約サービスを使用して複数サーバーのログを一元管理します。
460
+
461
+ **主要なログ集約サービス**: AWS CloudWatch, Datadog, Sentry, Loggly, Splunk
462
+
463
+ #### 8.1. AWS CloudWatch との統合
464
+
465
+ **Node.js**:
466
+ ```bash
467
+ npm install winston-cloudwatch
468
+ ```
469
+
470
+ ```typescript
471
+ import CloudWatchTransport from 'winston-cloudwatch';
472
+
473
+ const logger = winston.createLogger({
474
+ transports: [
475
+ new CloudWatchTransport({
476
+ logGroupName: '/aws/lambda/my-app',
477
+ logStreamName: () => {
478
+ const date = new Date().toISOString().split('T')[0];
479
+ return `${date}-${process.env.NODE_ENV}`;
480
+ },
481
+ awsRegion: 'us-east-1',
482
+ }),
483
+ ],
484
+ });
485
+ ```
486
+
487
+ #### 8.2. Datadog
488
+
489
+ **Node.js**:
490
+ ```bash
491
+ npm install dd-trace
492
+ ```
493
+
494
+ ```typescript
495
+ import tracer from 'dd-trace';
496
+ tracer.init({
497
+ logInjection: true, // ログに trace ID を自動追加
498
+ });
499
+
500
+ import logger from './logger';
501
+
502
+ logger.info('User action', {
503
+ userId: user.id,
504
+ action: 'purchase',
505
+ });
506
+ ```
507
+
508
+ #### 8.3. Sentry(エラートラッキング)
509
+
510
+ **Node.js**:
511
+ ```bash
512
+ npm install @sentry/node
513
+ ```
514
+
515
+ ```typescript
516
+ import * as Sentry from '@sentry/node';
517
+
518
+ Sentry.init({
519
+ dsn: process.env.SENTRY_DSN,
520
+ environment: process.env.NODE_ENV,
521
+ });
522
+
523
+ // エラーを Sentry に送信
524
+ try {
525
+ // 処理
526
+ } catch (error) {
527
+ Sentry.captureException(error);
528
+ logger.error('Error occurred', { error: error.message });
529
+ throw error;
530
+ }
531
+ ```
532
+
533
+ ### 9. パフォーマンスメトリクスの追加
534
+
535
+ パフォーマンス分析のため、実行時間やレスポンスタイムをログに記録します。
536
+
537
+ **汎用的な実装パターン(関数実行時間の記録)**:
538
+
539
+ **TypeScript/JavaScript の例**:
540
+ ```typescript
541
+ import logger from './logger';
542
+
543
+ function withTiming<T>(fn: () => T, operationName: string): T {
544
+ const start = Date.now();
545
+ try {
546
+ const result = fn();
547
+ const duration = Date.now() - start;
548
+ logger.debug('Operation completed', {
549
+ operation: operationName,
550
+ duration: `${duration}ms`,
551
+ status: 'success',
552
+ });
553
+ return result;
554
+ } catch (error) {
555
+ const duration = Date.now() - start;
556
+ logger.error('Operation failed', {
557
+ operation: operationName,
558
+ duration: `${duration}ms`,
559
+ status: 'error',
560
+ error: error.message,
561
+ });
562
+ throw error;
563
+ }
564
+ }
565
+
566
+ // 使用例
567
+ const users = withTiming(() => {
568
+ return db.query('SELECT * FROM users');
569
+ }, 'database.query.users');
570
+ ```
571
+
572
+ ### 10. ログの動作確認
573
+
574
+ **ローカル環境でのログ確認方法**:
575
+ ```bash
576
+ # ファイル出力の場合
577
+ tail -f logs/combined.log
578
+
579
+ # Docker の場合
580
+ docker logs -f <container_name>
581
+
582
+ # JSON ログを見やすく表示
583
+ tail -f logs/combined.log | jq .
584
+ ```
585
+
586
+ **確認すべき項目**:
587
+ - ログレベルが適切に設定されているか
588
+ - リクエスト ID が各ログエントリに含まれているか
589
+ - 機密情報が適切にマスキングされているか
590
+ - JSON 形式が正しいか(本番環境の場合)
591
+ - タイムスタンプが正しく記録されているか
592
+
593
+ ### 11. テストの実行
594
+
595
+ 既存のテストスイートを実行し、ログ機能が既存の機能に影響を与えていないことを確認します。
596
+
597
+ ```bash
598
+ # 例: npm/yarn/pnpm
599
+ npm test
600
+
601
+ # 例: pytest
602
+ pytest
603
+
604
+ # 例: Rails
605
+ bundle exec rspec
606
+ ```
607
+
608
+ ### 12. Git コミット
609
+
610
+ ```bash
611
+ git add src/utils/logger.ts
612
+ git add src/middleware/requestLogger.ts
613
+ git add src/
614
+
615
+ git commit -m "feat: add structured logging with Winston
616
+
617
+ - Add Winston logger with JSON format for production
618
+ - Add request logging middleware with request ID
619
+ - Mask sensitive data (password, token, apiKey)
620
+ - Add log rotation with daily-rotate-file
621
+ - Integrate with CloudWatch for centralized logging
622
+ - Add performance metrics logging
623
+
624
+ 🤖 Generated with [Claude Code](https://claude.com/claude-code)
625
+
626
+ Co-Authored-By: Claude <noreply@anthropic.com>"
627
+ ```
628
+
629
+ ## 完了条件
630
+
631
+ - ログライブラリがインストールされている
632
+ - ロガーが設定され、構造化ログが出力される
633
+ - リクエスト ID が追加され、トレーサビリティが確保されている
634
+ - 機密情報がマスキングされている
635
+ - ログレベル(ERROR, WARN, INFO, DEBUG)が適切に使い分けられている
636
+ - ログローテーションが設定されている(必要に応じて)
637
+ - ログ集約サービスとの統合が完了している(必要に応じて)
638
+ - すべてのテストが通る
639
+ - ログが期待通りに出力される
640
+
641
+ ## エスカレーション
642
+
643
+ - **ログが出力されない**:
644
+ - 「ログが出力されません。以下を確認してください:」
645
+ - ログレベルが適切か(DEBUG ログが INFO レベルで実行されていないか)
646
+ - ロガーが正しくインポートされているか
647
+ - 環境変数 `LOG_LEVEL` が設定されているか
648
+ - ファイル出力の場合、ディレクトリのアクセス権限
649
+
650
+ - **機密情報が漏洩している**:
651
+ - 「ログに機密情報が含まれています。以下を実施してください:」
652
+ - マスキングフィルターを追加
653
+ - 機密情報のキーワードリストを更新
654
+ - 既存ログを削除またはローテーション
655
+ - セキュリティチームに報告
656
+
657
+ - **ログが多すぎる / パフォーマンス影響**:
658
+ - 「ログ出力がパフォーマンスに影響しています。以下を検討してください:」
659
+ - ログレベルを INFO 以上に制限
660
+ - 非同期ログライブラリを使用(Pino など)
661
+ - サンプリング(1% のリクエストのみログ)
662
+ - 不要なログを削除
663
+
664
+ - **ログ集約サービスのコストが高い**:
665
+ - 「ログ集約サービスのコストが高騰しています。以下を検討してください:」
666
+ - ログレベルの見直し
667
+ - ログのサンプリング
668
+ - 保持期間の短縮
669
+ - ログ圧縮の有効化
670
+
671
+ ## ベストプラクティス
672
+
673
+ - **構造化ログ(JSON)を使用**: 検索・分析が容易
674
+ - **リクエスト ID を追加**: トレーサビリティの確保
675
+ - **ログレベルを適切に使い分け**: ERROR は即座に対応、INFO は重要なイベントのみ
676
+ - **機密情報を絶対に出力しない**: GDPR / PCI-DSS 違反に注意
677
+ - **環境による出力形式の切り替え**: 開発環境では可読性優先、本番環境では JSON
678
+ - **エラーにはスタックトレースを含める**: 問題調査の効率化
679
+ - **ログローテーションを設定**: ディスク容量の枯渇を防ぐ
680
+ - **ログ集約サービスの活用**: 分散システムでのログ統合
681
+ - **パフォーマンスメトリクスを追加**: レスポンスタイム、DB クエリ時間
682
+ - **ログレベルを環境変数で制御**: 本番環境で動的に変更可能に