# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Common Commands

```bash
# Build
make build                # Build audit-ng binary to bin/audit-ng

# Test
make test                 # Run all tests with verbose output
go test -v ./server -run TestName  # Run single test

# Lint
make lint                 # Run golangci-lint (v2.5.0)
make lint-fix             # Auto-fix linting issues

# Run locally
make run                  # Run with go run
./bin/audit-ng server --config config.yaml  # Run with config

# Docker
make docker-build         # Build Docker image (requires REGISTRY env var)
make docker-push          # Push to registry
```

## Architecture Overview

Audit-ng is a sidecar service that monitors TiDB audit/slow-query logs and uploads them to cloud storage.

```
┌─────────────────┐    ┌──────────────────────────────────┐    ┌─────────────────┐
│  TiDB/Kong      │    │           Audit-ng               │    │  Cloud Storage  │
│                 │    │                                  │    │                 │
│ • audit.log     │───▶│  Server.Run() main loop:        │───▶│  S3/GCS/Azure/  │
│ • slowlog       │    │  ├─ checkLogTick → pushLog()    │    │  AliCloud OSS   │
│                 │    │  ├─ cleanLogTick → cleanLog()   │    │                 │
└─────────────────┘    │  └─ ctx.Done() → rotateIfNeed() │    └─────────────────┘
                       │                  → final push    │
                       └──────────────────────────────────┘
```

### Key Components

**Server** (`server/server.go`): Main orchestration loop with ticker-based scheduling:
- `checkLogTick`: Triggers log rotation check and push operations
- `cleanLogTick`: Disk space management and slow log cleanup
- Hot config reload via `viper.WatchConfig()`

**LogHandler Interface** (`server/handler.go`): Storage backend abstraction:
```go
type LogHandler interface {
    Push(ctx context.Context, fname string, targetKey string) error
    Close()
}
```
Implementations: `S3Handler`, `GCSHandler`, `AZBlobHandler`, `OSSHandler` (AliCloud), `NoPushHandler`

**Rotation Strategies** (`server/rotation.go`):
- `rename`: Default lumberjack-based rename (requires app to reopen file)
- `copytruncate`: Copy then truncate (for apps without SIGHUP support)

### Operating Modes

**tidb mode** (default): TiDB-specific features including:
- JSON/TEXT format switch detection via `rotateIfLogFormatChanged()`
- Auto prefix detection (tidb-/kong-) from pod name

**agent mode**: Generic mode for non-TiDB workloads:
- Uses `SubPath` config for bucket path
- No format switch detection

### Configuration

Config via YAML file or environment variables (viper). Key fields in `server/config.go`:
- `bucketURL`: Target storage (s3://bucket/path, gcs://..., https://...blob.core.windows.net/...)
- `mode`: "tidb" or "agent"
- `rotationStrategy`: "rename" or "copytruncate"
- `pushTrigger`: Push behavior tuning (see below)

### Push Trigger Configuration

- `checkInterval`, `cleanInterval`, `filesPerPush`: apply to both `tidb` and `agent` modes
- `maxSize`, `maxLifetime`: only apply to `agent` mode

```yaml
pushTrigger:
  checkInterval: 5s      # Check interval (both modes; min: 1s, default: 5s)
  cleanInterval: 10s     # Cleanup interval (both modes; min: 1s, default: 10s)
  filesPerPush: 3        # Files per push cycle (both modes; null/0=default 3)
  maxSize: 5             # Size threshold in MiB (agent mode only; null=5, 0=disabled, max=10240)
  maxLifetime: 300       # Time threshold in seconds (agent mode only; null=300, 0=disabled, max=86400)
```

**Semantic explanation**:
- `filesPerPush`: `null`/unset or `0` → Use default value (3); positive number → Use the configured value
- `maxSize`, `maxLifetime`: `null`/unset → Use default value; `0` → Explicitly disabled; positive number → Use the configured value

**Overflow protection**:
- `maxSize` is capped at 10240 MiB (10 GiB) to prevent int64 overflow
- `maxLifetime` is capped at 86400 s (24 hours) to prevent overflow

### Cloud Auth Patterns

- **AWS**: IRSA (default) or explicit `AssumeRole` with `aws.roleARN`
- **GCP**: Workload Identity (automatic)
- **Azure**: SAS token via `azure.sasToken`
- **AliCloud**: RRSA or `AssumeRole` with `alicloud.roleARN`

## Testing Patterns

- Uses testify framework with `require` for critical assertions
- Mock handler: `MockLogHandler` in `gomock_handler.go`
- Test files mirror source files: `server.go` → `server_test.go`
- Table-driven tests preferred for multiple scenarios

## Code Patterns to Follow

- Error wrapping: Use `github.com/pingcap/errors` for annotation
- Logging: Use `github.com/pingcap/log` with zap fields
- Config validation: Add validators in `server/config.go` (e.g., `validateMode()`)
- Metrics: Define in `server/metrics.go`, register with Prometheus

## Key Metrics (for debugging)

All metrics have subsystem `auditlog`:
- `auditlog_push_log_total{result=success|fail}`: Push operation counter
- `auditlog_push_file_duration_seconds`: Push latency histogram
- `auditlog_storage_size_available_bytes`: Disk space monitoring
- `auditlog_delete_log_file_due_to_disk_full_total`: Disk pressure indicator
- `auditlog_pending_push_files`: Backlog of rotated audit log files pending push
