# iOS Logging Guide - How to Check Logs for Errors

**Purpose:** Quick reference for viewing iOS app logs during development and debugging

**Last Updated:** 2025-11-15  
**Status:** 🎯 **ACTIVE** - Reference guide for iOS debugging

---

## Quick Start

**Most Common Methods (in order of ease):**

1. **Xcode Console** (when app is running in Xcode) - Easiest
2. **Console.app** (macOS system console) - Good for background logs
3. **Command-line** (`xcrun simctl`) - Best for automation/scripts

---

## Method 1: Xcode Console (Recommended for Development)

**When to use:** App is running in Xcode (simulator or device)

### Steps:

1. **Open Xcode** and run your app (Cmd+R)
2. **Open Debug Area:**
   - Press **Cmd+Shift+Y** (or View → Debug Area → Activate Console)
   - Or click the bottom panel icon in Xcode
3. **Filter logs:**
   - Click the search box at bottom of console
   - Type: `DNP-` or `DailyNotification` or `Error`
   - Press Enter

### Filter Examples:

```
DNP-PLUGIN    # Plugin operations
DNP-FETCH     # Background fetch operations
DNP-SCHEDULER # Scheduling operations
DNP-STORAGE   # Storage operations
Error         # All errors
```

### Copy-Paste Commands (LLDB Console):

When app is running, you can also use LLDB commands in Xcode console:

```swift
// Check pending notifications
po UNUserNotificationCenter.current().pendingNotificationRequests()

// Check permission status
po await UNUserNotificationCenter.current().notificationSettings()

// Manually trigger BGTask (simulator only)
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"org.timesafari.dailynotification.fetch"]
```

---

## Method 2: Console.app (macOS System Console)

**When to use:** App is running in background, or you want to see system-level logs

### Steps:

1. **Open Console.app:**
   - Press **Cmd+Space** (Spotlight)
   - Type: `Console`
   - Press Enter
   - Or: Applications → Utilities → Console

2. **Select Device/Simulator:**
   - In left sidebar, expand "Devices"
   - Select your simulator or connected device
   - Or select "All Logs" for system-wide logs

3. **Filter logs:**
   - Click search box (top right)
   - Type: `DNP-` or `org.timesafari.dailynotification`
   - Press Enter

### Filter by Subsystem (Structured Logging):

The plugin uses structured logging with subsystems:

```
org.timesafari.dailynotification.plugin    # Plugin operations
org.timesafari.dailynotification.fetch    # Fetch operations
org.timesafari.dailynotification.scheduler # Scheduling operations
org.timesafari.dailynotification.storage    # Storage operations
```

**To filter by subsystem:**
- In Console.app search: `subsystem:org.timesafari.dailynotification`

---

## Method 3: Command-Line (xcrun simctl)

**When to use:** Automation, scripts, or when Xcode/Console.app aren't available

### Stream Live Logs (Simulator):

```bash
# Stream all logs from booted simulator
xcrun simctl spawn booted log stream

# Stream only plugin logs (filtered)
xcrun simctl spawn booted log stream --predicate 'subsystem == "org.timesafari.dailynotification"'

# Stream with DNP- prefix filter
xcrun simctl spawn booted log stream | grep "DNP-"
```

### Save Logs to File:

```bash
# Save all logs to file
xcrun simctl spawn booted log stream > device.log 2>&1

# Save filtered logs
xcrun simctl spawn booted log stream --predicate 'subsystem == "org.timesafari.dailynotification"' > plugin.log 2>&1

# Then analyze with grep
grep -E "\[DNP-(FETCH|SCHEDULER|PLUGIN)\]" device.log
```

### View Recent Logs (Not Streaming):

```bash
# Show recent logs (last 100 lines)
xcrun simctl spawn booted log show --last 1m | grep "DNP-"

# Show logs for specific time range
xcrun simctl spawn booted log show --start "2025-11-15 10:00:00" --end "2025-11-15 11:00:00" | grep "DNP-"
```

### Physical Device Logs:

```bash
# List connected devices
xcrun devicectl list devices

# Stream logs from physical device (requires device UDID)
xcrun devicectl device process launch --device <UDID> org.timesafari.dailynotification.test

# Or use Console.app for physical devices (easier)
```

---

## Method 4: Validate Log Sequence (Automated)

**When to use:** Testing prefetch cycles, verifying complete execution

### Using Validation Script:

```bash
# From log file
./scripts/validate-ios-logs.sh device.log

# From live stream
xcrun simctl spawn booted log stream --predicate 'subsystem == "org.timesafari.dailynotification"' | ./scripts/validate-ios-logs.sh

# From filtered grep
grep -E "\[DNP-(FETCH|SCHEDULER|PLUGIN)\]" device.log | ./scripts/validate-ios-logs.sh
```

**See:** `scripts/validate-ios-logs.sh` for complete validation script

---

## Common Log Prefixes

**Plugin Logs (look for these):**

| Prefix | Meaning | Example |
|--------|---------|---------|
| `[DNP-PLUGIN]` | Main plugin operations | `[DNP-PLUGIN] configure() called` |
| `[DNP-FETCH]` | Background fetch operations | `[DNP-FETCH] BGTask handler invoked` |
| `[DNP-SCHEDULER]` | Notification scheduling | `[DNP-SCHEDULER] Scheduling notification` |
| `[DNP-STORAGE]` | Storage/DB operations | `[DNP-STORAGE] Persisted schedule` |
| `[DNP-DEBUG]` | Debug diagnostics | `[DNP-DEBUG] Plugin class found` |

**Error Indicators:**

- `Error:` - System errors
- `Failed:` - Operation failures
- `❌` - Visual error markers in logs
- `⚠️` - Warning markers

---

## Troubleshooting Common Issues

### Issue: No logs appearing

**Solutions:**
1. **Check app is running:** App must be launched to generate logs
2. **Check filter:** Remove filters to see all logs
3. **Check log level:** Some logs may be at debug level only
4. **Restart logging:** Close and reopen Console.app or restart log stream

### Issue: Too many logs (noise)

**Solutions:**
1. **Use specific filters:** `DNP-` instead of `DailyNotification`
2. **Filter by subsystem:** `subsystem:org.timesafari.dailynotification`
3. **Use time range:** Only show logs from last 5 minutes
4. **Use validation script:** Automatically filters for important events

### Issue: Can't see background task logs

**Solutions:**
1. **Use Console.app:** Background tasks show better in system console
2. **Check Background App Refresh:** Must be enabled for BGTask logs
3. **Use log stream:** `xcrun simctl spawn booted log stream` shows all logs
4. **Check predicate:** Use `--predicate` to filter specific subsystems

### Issue: Physical device logs not showing

**Solutions:**
1. **Use Console.app:** Easiest for physical devices
2. **Check device connection:** Device must be connected and trusted
3. **Check provisioning:** Device must be provisioned for development
4. **Use Xcode:** Xcode → Window → Devices and Simulators → View Device Logs

---

## Quick Reference Commands

### Copy-Paste Ready Commands:

```bash
# Stream plugin logs (simulator)
xcrun simctl spawn booted log stream --predicate 'subsystem == "org.timesafari.dailynotification"'

# Save logs to file
xcrun simctl spawn booted log stream > device.log 2>&1

# View recent errors
xcrun simctl spawn booted log show --last 5m | grep -i "error\|failed\|DNP-"

# Validate log sequence
grep -E "\[DNP-(FETCH|SCHEDULER|PLUGIN)\]" device.log | ./scripts/validate-ios-logs.sh

# Check app logs only
xcrun simctl spawn booted log stream --predicate 'process == "App"'
```

---

## Log Levels and Filtering

**iOS Log Levels:**
- **Default:** Shows Info, Error, Fault
- **Debug:** Shows Debug, Info, Error, Fault
- **Error:** Shows Error, Fault only

**To see debug logs:**
- In Xcode: Product → Scheme → Edit Scheme → Run → Arguments → Environment Variables
- Add: `OS_ACTIVITY_MODE=disable` (shows all logs including debug)

**Or use Console.app:**
- Action menu → Include Info Messages
- Action menu → Include Debug Messages

---

## References

- **Testing Guide:** `doc/test-app-ios/IOS_PREFETCH_TESTING.md` - Comprehensive testing procedures
- **Test App Requirements:** `doc/test-app-ios/IOS_TEST_APP_REQUIREMENTS.md` - Debugging section
- **Validation Script:** `scripts/validate-ios-logs.sh` - Automated log sequence validation
- **Main Directive:** `doc/directives/0003-iOS-Android-Parity-Directive.md` - Implementation details

---

**Status:** 🎯 **READY FOR USE**  
**Maintainer:** Matthew Raymer

