# How to Troubleshoot SmsForwarder Message Forwarding Failures Using Logs

> Troubleshoot SmsForwarder message forwarding failures with ease. Learn to effectively use local logs and Logcat to diagnose and resolve issues. Essential guide for developers.

- Repository: [pppscn/SmsForwarder](https://github.com/pppscn/SmsForwarder)
- Tags: how-to-guide
- Published: 2026-06-22

---

**SmsForwarder logs every forwarding step via Android WorkManager classes (e.g., `SendWorker`, `UpdateLogsWorker`) to both a local Room database (`Logs` table) and Logcat, allowing you to diagnose failures by inspecting the Logs UI or filtering Logcat for worker-specific tags like `SendWorker:E`.**

SmsForwarder (available at pppscn/SmsForwarder) is an open-source Android application that automates SMS, call, and notification forwarding to multiple channels. When messages fail to reach their configured destinations, the application provides diagnostic visibility through a custom `Log` wrapper and persistent database entries. Understanding how to access and interpret these logs is essential for resolving silent-period blocks, rule mismatches, and network configuration errors.

## Understanding the SmsForwarder Logging Architecture

### The Worker-Based Processing Pipeline

SmsForwarder processes incoming events through dedicated **Worker** classes in the `cn.ppps.forwarder.workers` package. Each worker handles a specific phase of the forwarding lifecycle and emits detailed debug information via the custom `Log` utility (wrapping `Log.d` and `Log.e` calls).

The primary workers responsible for logging include:

- **SendWorker**: Handles core forwarding logic, rule matching, silent-period validation, and duplicate filtering
- **UpdateLogsWorker**: Manages uploading local log entries to remote servers
- **NetworkWorker**: Validates network state conditions against task requirements
- **SimWorker**: Verifies SIM card slot and state requirements
- **LocationWorker**: Checks location-based forwarding conditions

### The Logs Database and UI Layer

Every forwarding attempt creates a persistent record in the **Logs** table defined in [`cn.ppps.forwarder.database.entity.Logs.kt`](https://github.com/pppscn/SmsForwarder/blob/main/cn.ppps.forwarder.database.entity.Logs.kt). The **LogsFragment** ([`app/src/main/kotlin/cn/ppps/forwarder/fragment/LogsFragment.kt`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/kotlin/cn/ppps/forwarder/fragment/LogsFragment.kt)) provides the main interface for browsing these entries, reading data through the **LogsViewModel** → **LogsRepository** → **LogsDao** chain.

## Step-by-Step Troubleshooting Workflow

Follow this systematic approach to identify why a message failed to forward:

1. **Enable verbose logging** – The app logs at `DEBUG` level by default. For additional detail, ensure `Log.isDebug = true` is set via the app's settings (this flag is managed by `SettingUtils`).

2. **Reproduce the failure** – Trigger the specific SMS, call, or app notification that should be forwarded to generate fresh log entries.

3. **Open the Logs view** – Navigate to the **Logs** screen from the main UI (listed under *Message History*). This fragment queries the database through `LogsViewModel` to display timestamps, sender IDs, and rule associations.

4. **Filter by tag or task** – Each worker logs with a tag equal to its class name. Use the built-in filter UI or search Logcat for specific tags like `SendWorker` or `UpdateLogsWorker` to isolate the relevant processing step.

5. **Interpret key log entries** – Examine the specific worker logs for error signatures (detailed in the next section).

6. **Check the database entry** – Each forward attempt inserts a `Logs` record via `Core.logs.insert(log)`. Open the entry in the UI to see the exact failure reason, including optional comments like `ResUtils.getString(R.string.silent_time_period)` for silent-period blocks.

7. **Use Logcat for low-level issues** – If the UI shows no entry (indicating a crash before DB insertion), attach Android Studio or run `adb logcat` filtered by the package name `cn.ppps.forwarder`.

## Interpreting Worker Log Entries

### SendWorker Logs

The `SendWorker` class ([`app/src/main/kotlin/cn/ppps/forwarder/workers/SendWorker.kt`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/kotlin/cn/ppps/forwarder/workers/SendWorker.kt)) logs the complete forwarding pipeline:

- **Start of forwarding**: `Log.d(TAG, "SendWorker start...")`
- **Silent-period checks**: Logs when the current time falls within `SettingUtils.silentPeriodStart/End`
- **Duplicate filtering**: Validates against `SettingUtils.duplicateMessagesLimits`
- **Rule matching**: Logs `rule.toString()` for each evaluated rule before attempting sends

Errors appear as `Log.e(TAG, "SendWorker error: …")` with specific failure contexts.

### UpdateLogsWorker Logs

Located in [`app/src/main/kotlin/cn/ppps/forwarder/workers/UpdateLogsWorker.kt`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/kotlin/cn/ppps/forwarder/workers/UpdateLogsWorker.kt), this worker handles remote log synchronization:

- **Success**: `Log.d("UpdateLogsWorker", "UpdateLogsWorker sendResponseJson: …")`
- **Failure**: `Log.e("UpdateLogsWorker", "UpdateLogsWorker error: …")` (indicates server unreachability or authentication issues)

### Condition Workers

NetworkWorker, SimWorker, and LocationWorker log condition validation failures with structured messages like:

```

Log.d(TAG, "TASK-123：networkState is not match…")

```

## Common Failure Patterns and Log Signatures

| Failure scenario | Log messages | Likely cause |
|------------------|--------------|--------------|
| **Silent-period blocking** | `Log.e(TAG, "免打扰(禁用转发)时间段")` | `SettingUtils.silentPeriodStart/End` covers the current time and `enableSilentPeriodLogs` is disabled |
| **Duplicate-message filtering** | `Log.e(TAG, "过滤重复消息机制")` | `SettingUtils.duplicateMessagesLimits` is too low; identical payload arrived within the deduplication window |
| **No matching rule** | `Log.d(TAG, rule.toString())` followed by `Result.failure` without `Log.e` | Incoming message type or SIM slot does not satisfy any active rule's conditions |
| **Condition mismatch** | `Log.d(TAG, "TASK-…：networkState is not match…")` | The task's network, SIM, or location prerequisites are not met |
| **Remote log upload failure** | `Log.e("UpdateLogsWorker", "UpdateLogsWorker error: …")` | Remote server unreachable or API authentication failure |

## Querying Logs Programmatically

When debugging advanced scenarios, you can inspect logs directly via the database layer:

### Retrieve Recent Log Entries

```kotlin
// Query the last 20 log entries from the DB
val recentLogs = Core.logs.query(limit = 20, orderDesc = true)
recentLogs.forEach {
    Log.d("DebugHelper", "Log ${it.id}: ${it.msg} – sender ${it.senderId}, rule ${it.ruleId}")
}

```

### Manually Trigger Log Upload

Useful when the UI shows "Pending" status for remote log synchronization:

```kotlin
val work = OneTimeWorkRequestBuilder<UpdateLogsWorker>()
    .setInputData(workDataOf("logId" to logId))
    .build()
WorkManager.getInstance(context).enqueue(work)

```

### Filter Logcat for Specific Workers

```bash

# Show only error-level logs from SendWorker

adb logcat -s SendWorker:E

# Filter for all SmsForwarder workers

adb logcat -s SendWorker:D -s UpdateLogsWorker:D -s NetworkWorker:D

```

## Summary

- SmsForwarder uses **Worker** classes (`SendWorker`, `UpdateLogsWorker`, etc.) to process messages, with each step logged via a custom `Log` wrapper
- Failed forwards persist in the **Logs** database table (`cn.ppps.forwarder.database.entity.Logs`) and are viewable through **LogsFragment**
- Enable `Log.isDebug = true` via `SettingUtils` for verbose output before reproducing the issue
- Filter Logcat by worker tags (e.g., `SendWorker:E`) to isolate specific failure points like silent-period blocks or rule mismatches
- Common failures include duplicate-message filtering, condition mismatches (network/SIM/location), and remote server upload errors

## Frequently Asked Questions

### Where are SmsForwarder logs stored?

SmsForwarder stores forwarding history in a local **Room database** table named `Logs` (defined in [`app/src/main/kotlin/cn/ppps/forwarder/database/entity/Logs.kt`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/kotlin/cn/ppps/forwarder/database/entity/Logs.kt)). The UI accesses this data through `LogsRepository` to display entries in **LogsFragment**. Additionally, debug logs are emitted to Android Logcat with worker-specific tags like `SendWorker` and `UpdateLogsWorker`.

### How do I enable debug logging in SmsForwarder?

Debug logging is controlled by the `Log.isDebug` flag, which is read from `SettingUtils` in the app's settings. When enabled, workers emit detailed `Log.d` statements showing rule evaluation, condition checks, and HTTP request/response details. For command-line debugging, use `adb logcat -s SendWorker:D` to capture debug-level output from the forwarding worker.

### Why does my message show "Silent period" in the logs?

This indicates the current time falls within the **silent period** configured in `SettingUtils.silentPeriodStart` and `SettingUtils.silentPeriodEnd`. When active and `enableSilentPeriodLogs` is disabled, `SendWorker` logs `Log.e(TAG, "免打扰(禁用转发)时间段")` and aborts forwarding. Adjust the time window in settings or disable the silent period feature to allow forwarding during those hours.

### How can I check why a specific rule didn't match?

`SendWorker` logs each rule evaluation via `Log.d(TAG, rule.toString())` before attempting to match. If no rule matches, you will see the rule dump followed by a `Result.failure` without an accompanying `Log.e`. Compare the logged rule conditions (SIM slot, sender pattern, content regex) against the incoming message metadata visible in the **Logs** UI to identify the mismatch.