# Docker JSON Logging

Dokumentation für strukturierte JSON-Logs in Docker Containern für Log-Aggregation.

## Übersicht

Das Framework verwendet automatisch strukturierte JSON-Logs in Production Docker-Umgebungen, um die Integration mit Log-Aggregatoren (Elasticsearch, Datadog, CloudWatch, etc.) zu ermöglichen.

## Automatische Handler-Aktivierung

### Development Mode (Standard)
```
PHP CLI in Docker → DockerJsonHandler (Pretty-Printed)
- Strukturiertes JSON mit Einrückung für bessere Lesbarkeit
- Alle Log-Aggregator-Felder enthalten
- Debugging-freundlich
- Lokale Docker-Entwicklung optimiert
```

**Beispiel-Output**:
```json
{
    "timestamp": "2025-10-22T17:14:25+00:00",
    "@timestamp": "2025-10-22T17:14:25+00:00",
    "level": "INFO",
    "level_value": 200,
    "severity": 6,
    "channel": "app",
    "message": "Development test message",
    "environment": "development",
    "host": "3be143247465",
    "service": "dev-service",
    "context": {
        "user_id": 123,
        "action": "test"
    }
}
```

### Production Mode
```
PHP CLI in Docker → DockerJsonHandler (Compact)
- Kompakte JSON-Ausgabe (eine Zeile pro Log)
- Alle Log-Aggregator-Felder enthalten
- Optimiert für maschinelle Verarbeitung und Log-Aggregatoren
```

**Beispiel-Output**:
```json
{"timestamp":"2025-10-22T17:14:25+00:00","@timestamp":"2025-10-22T17:14:25+00:00","level":"INFO","level_value":200,"severity":6,"channel":"app","message":"Production log","environment":"production","host":"3be143247465","service":"api-service","context":{"user_id":123}}
```

### Lokale Entwicklung (ohne Docker)
```
PHP CLI lokal → ConsoleHandler
- Farbige, interaktive Console-Ausgabe
- Optimiert für lokale Terminal-Sessions
```

## Detection-Logik

```php
// Automatische Docker-Erkennung
$inDocker = file_exists('/.dockerenv') || getenv('DOCKER_CONTAINER') === 'true';

if ($inDocker && $config->app->isProduction()) {
    // DockerJsonHandler für Production
} else {
    // ConsoleHandler für Development
}
```

## JSON-Format

Jeder Log-Eintrag wird als **eine Zeile JSON** ausgegeben:

```json
{
  "timestamp": "2025-10-22T19:08:43+02:00",
  "@timestamp": "2025-10-22T19:08:43+02:00",
  "level": "INFO",
  "level_value": 200,
  "severity": 6,
  "channel": "app",
  "message": "User logged in",
  "environment": "production",
  "host": "3be143247465",
  "service": "api-service",
  "context": {
    "user_id": 12345,
    "ip_address": "192.168.1.1"
  }
}
```

## Standard-Felder

| Feld | Typ | Beschreibung |
|------|-----|--------------|
| `timestamp` | string | ISO 8601 Zeitstempel |
| `@timestamp` | string | Elasticsearch-konformer Zeitstempel |
| `level` | string | Log-Level Name (DEBUG, INFO, WARNING, ERROR, etc.) |
| `level_value` | int | Numerischer Log-Level Wert (100-600) |
| `severity` | int | RFC 5424 Severity Level (0-7) |
| `channel` | string\|null | Log-Channel (app, security, database, etc.) |
| `message` | string | Log-Nachricht |
| `environment` | string | Deployment-Umgebung (production, staging, development) |
| `host` | string | Container/Server Hostname |
| `service` | string | Service-Name (aus APP_NAME env var) |
| `context` | object | Strukturierte Kontext-Daten |
| `extra` | object | Zusätzliche Metadaten (optional) |

## Docker Logs Verwendung

### Basis-Kommandos

```bash
# Letzte 50 Logs anzeigen
docker logs php --tail 50

# Logs live verfolgen
docker logs php --follow

# Logs seit bestimmter Zeit
docker logs php --since 10m
docker logs php --since "2025-10-22T18:00:00"
```

### Mit jq formatieren

```bash
# Pretty-print JSON
docker logs php 2>&1 | jq .

# Nur ERROR Logs
docker logs php 2>&1 | jq 'select(.level == "ERROR")'

# Nur CRITICAL und höher
docker logs php 2>&1 | jq 'select(.severity <= 2)'

# Als TSV (Tab-separated)
docker logs php 2>&1 | jq -r '[.timestamp, .level, .message] | @tsv'

# Gruppierung nach Level
docker logs php 2>&1 | jq -s 'group_by(.level) | map({level: .[0].level, count: length})'

# Fehler mit Context
docker logs php 2>&1 | jq 'select(.level == "ERROR") | {timestamp, message, context}'
```

### Erweiterte Filterung

```bash
# Logs von bestimmtem Service
docker logs php 2>&1 | jq 'select(.service == "api-service")'

# Logs mit bestimmtem User
docker logs php 2>&1 | jq 'select(.context.user_id == 12345)'

# Performance-Logs (> 1 Sekunde)
docker logs php 2>&1 | jq 'select(.context.duration_ms > 1000)'

# Security-Channel Logs
docker logs php 2>&1 | jq 'select(.channel == "security")'
```

## Log-Aggregator Integration

### Elasticsearch

Die JSON-Logs sind direkt Elasticsearch-kompatibel:

```json
{
  "@timestamp": "2025-10-22T19:08:43+02:00",  // Elasticsearch convention
  "severity": 6,                               // RFC 5424 numeric
  "environment": "production",
  "host": "3be143247465",
  "service": "api-service"
}
```

**Filebeat Konfiguration**:
```yaml
filebeat.inputs:
- type: container
  paths:
    - '/var/lib/docker/containers/*/*.log'
  json.keys_under_root: true
  json.add_error_key: true
  processors:
    - add_docker_metadata: ~
```

### Datadog

**Docker Compose Konfiguration**:
```yaml
services:
  php:
    labels:
      - "com.datadoghq.ad.logs=[{\"source\":\"php\",\"service\":\"api-service\"}]"
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
```

### CloudWatch

**Fluent Bit Konfiguration**:
```ini
[INPUT]
    Name              tail
    Path              /var/lib/docker/containers/*/*.log
    Parser            docker
    Tag               php.*

[OUTPUT]
    Name              cloudwatch_logs
    Match             php.*
    region            eu-central-1
    log_group_name    /aws/ecs/php-service
    log_stream_prefix app/
```

## Environment-Konfiguration

### Production Aktivierung

```env
# .env
APP_ENV=production
APP_DEBUG=false
APP_NAME=api-service
```

### Docker Environment Variable

Optional kann Docker-Detection explizit aktiviert werden:

```yaml
# docker-compose.yml
services:
  php:
    environment:
      - DOCKER_CONTAINER=true
```

## Testing

### Manueller Test

```bash
# In Container ausführen
docker exec php php tests/debug/test-docker-json-logging.php

# Output prüfen
docker exec php php tests/debug/test-docker-json-logging.php 2>&1 | jq .
```

### Unit Tests

```bash
# Logging Tests ausführen
./vendor/bin/pest tests/Unit/Framework/Logging/
```

## Performance

**Charakteristiken**:
- **Latenz**: <1ms pro Log-Eintrag
- **Overhead**: ~5% gegenüber einfacher String-Ausgabe
- **Throughput**: >10,000 Logs/Sekunde
- **Memory**: Konstanter Speicherverbrauch (kein Buffering)

**Optimierungen**:
- Kompakte JSON-Ausgabe (keine Pretty-Print Formatierung)
- Direkte STDOUT-Ausgabe ohne Buffering
- Minimaler Serialisierungs-Overhead durch JsonSerializer

## Troubleshooting

### JSON-Logs erscheinen nicht in docker logs

**Mögliche Ursachen**:
1. APP_ENV ist nicht auf "production" gesetzt
2. Logs werden nicht in CLI-Mode generiert (nur Web-Requests)
3. Docker-Detection schlägt fehl

**Lösung**:
```bash
# Environment prüfen
docker exec php php -r "echo getenv('APP_ENV') . PHP_EOL;"

# Docker-Detection prüfen
docker exec php php -r "var_dump(file_exists('/.dockerenv'));"

# SAPI prüfen
docker exec php php -r "echo PHP_SAPI . PHP_EOL;"
```

### JSON ist nicht valide

**Ursache**: Multi-line Ausgabe von anderen Komponenten

**Lösung**: Nur JSON-Zeilen filtern
```bash
docker logs php 2>&1 | grep '^{' | jq .
```

### Zu viele Logs

**Lösung**: Log-Level erhöhen
```env
# .env
LOG_LEVEL=WARNING  # Nur WARNING und höher
```

## Best Practices

### 1. Strukturierte Kontext-Daten

✅ **Good**:
```php
$logger->info('User action', LogContext::withData([
    'user_id' => $userId,
    'action' => 'login',
    'ip_address' => $ipAddress
]));
```

❌ **Bad**:
```php
$logger->info("User $userId logged in from $ipAddress");
```

### 2. Konsistente Field-Names

Verwende snake_case für Context-Keys:
```php
LogContext::withData([
    'user_id' => 123,        // ✅ snake_case
    'request_id' => 'abc',   // ✅ snake_case
    'userId' => 123          // ❌ camelCase
]);
```

### 3. Sensitive Daten vermeiden

Niemals Passwörter, Tokens oder PII in Logs:
```php
// ❌ Schlecht
$logger->info('Login', ['password' => $password]);

// ✅ Gut
$logger->info('Login', ['user_id' => $userId]);
```

### 4. Richtige Log-Levels

- **DEBUG**: Detaillierte Debugging-Informationen
- **INFO**: Informative Ereignisse (User-Login, API-Calls)
- **WARNING**: Warnungen (Deprecated-API-Usage)
- **ERROR**: Fehler (Database-Errors, External-API-Failures)
- **CRITICAL**: Kritische Fehler (System-Ausfall)

## Weiterführende Dokumentation

- [Log-Aggregator-Felder](./aggregator-fields.md)
- [Structured Logging Best Practices](./structured-logging.md)
- [Performance Tuning](./performance.md)
