docs: add logging instruction reference to tasks
This commit is contained in:
90
docs/InstructionsLogging.md
Normal file
90
docs/InstructionsLogging.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Logging Instructions
|
||||
|
||||
This document describes how to write and refactor logging across the AniWorld codebase to make logs **human-readable**, **debug-friendly**, and **noise-free**.
|
||||
|
||||
> ✅ Goal: Logs should help a developer understand what happened, why it happened, and what to inspect next — without overwhelming them with duplicates or irrelevant details.
|
||||
|
||||
---
|
||||
|
||||
## 1. Principles for Great Logs
|
||||
|
||||
### 1.1 Use the Right Log Level
|
||||
|
||||
- `DEBUG`: Detailed internal state useful when debugging a specific issue (e.g., decision points, returned values, request/response payloads). Not for normal operation.
|
||||
- `INFO`: High-level events that represent what the system is doing (e.g., "Import started", "New series added", "Config reloaded"). Use sparingly.
|
||||
- `WARNING`: Something unexpected happened, but the system can continue (e.g., missing optional file, fallback behavior).
|
||||
- `ERROR`: An operation failed and needs attention (e.g., exception caught, failed database write).
|
||||
- `CRITICAL`: The system is in an unusable state (e.g., config corruption, failed startup).
|
||||
|
||||
### 1.2 Keep Logs Human-Readable
|
||||
|
||||
- Write messages in a clear, descriptive sentence-style format.
|
||||
- Avoid cryptic codes or single-word log messages.
|
||||
- Prefer `logger.debug("... %s", value)`-style formatting over f-strings to avoid unnecessary work when the log level is disabled.
|
||||
|
||||
### 1.3 Avoid Log Spam
|
||||
|
||||
- Don’t log inside hot loops unless you explicitly aggregate and log a summary (e.g., "Processed 124 files, 3 failures").
|
||||
- Avoid repeated/logging the same event at the same level (e.g., do not log "Retrying" 10 times at INFO; log once at INFO and then use DEBUG for each retry).
|
||||
- Use rate limiting or debounce patterns for logs that can fire rapidly (e.g., external service health checks).
|
||||
- Prefer a single higher-level log with context rather than many low-level logs that clutter output.
|
||||
|
||||
### 1.4 Log Objects Usefully
|
||||
|
||||
- When logging objects, log the minimal useful representation (e.g., ID, name, status) rather than the full object or its memory address.
|
||||
- If an object has a `.dict()`, `.to_dict()`, or `.as_dict()` helper (common in Pydantic models), log that rather than relying on `repr()`.
|
||||
- Add a `__repr__` or `__str__` implementation to domain models that returns a helpful, concise string with key identifiers.
|
||||
- Use structured logging (e.g., `logger.info("Series added", extra={"series_id": series.id, "title": series.title})`) where supported.
|
||||
- For exceptions, prefer `logger.exception("Failed to ...")` to capture stack traces.
|
||||
|
||||
---
|
||||
|
||||
## 2. Refactoring Existing Logs
|
||||
|
||||
When improving or refactoring existing log statements, aim to make them:
|
||||
|
||||
- **Actionable**: A developer reading the log should know what happened and what to check next.
|
||||
- **Non-redundant**: Remove duplicates and ensure only one log records the same high-level event at a given level.
|
||||
- **Context-rich**: Include identifiers (e.g., `series_id`, `file_path`, `user_id`) and key state that explains why a decision was made.
|
||||
- **Level-appropriate**: Downgrade noisy INFO logs to DEBUG, and elevate critical failures to ERROR/CRITICAL.
|
||||
|
||||
### 2.1 Refactor Checklist
|
||||
|
||||
1. **Locate noisy logs**: Search for repeated messages (e.g., "Start", "Done") and determine whether they should be DEBUG or removed.
|
||||
2. **Replace ad-hoc prints**: Remove `print()` statements or `print(obj)` and replace with `logger.*` calls.
|
||||
3. **Use structured context**: If a function logs multiple related messages, include the same context in each (e.g., `extra={"series_id": series.id}`) or use a context manager that attaches it.
|
||||
4. **Validate object output**: Ensure any logged object produces a useful representation (add methods or translate to dict). If not, log the key fields explicitly.
|
||||
5. **Batch repetitive events**: If a loop logs per item, consider collecting stats and logging a summary at the end.
|
||||
|
||||
## 3. Adding New Logs
|
||||
|
||||
When adding logs to new code paths:
|
||||
|
||||
- Log **important state transitions** (e.g., "Queue started", "Download completed", "Config reloaded").
|
||||
- For error paths, include what failed and why (e.g., "Could not load config from X: {exc}").
|
||||
- Prefer logging at the boundaries of operations, not deep inside utility functions unless it aids debugging.
|
||||
- Write logs in full sentences, with a clear subject, verb, and object.
|
||||
|
||||
---
|
||||
|
||||
## 4. Example Patterns
|
||||
|
||||
```python
|
||||
logger.info("Import completed", extra={"series_id": series.id, "count": len(imported)})
|
||||
|
||||
logger.debug(
|
||||
"Fetched feed items",
|
||||
extra={"feed_url": feed.url, "item_count": len(items)},
|
||||
)
|
||||
|
||||
try:
|
||||
result = download_episode(episode)
|
||||
except Exception:
|
||||
logger.exception("Failed to download episode %s", episode.id)
|
||||
```
|
||||
|
||||
> 💡 When in doubt, favor **fewer, richer logs** over many noisy logs.
|
||||
|
||||
# importent
|
||||
|
||||
note which file is done.
|
||||
Reference in New Issue
Block a user