frappe-core-logging
Originally fromopenaec-foundation/frappe_claude_skill_package
Installation
SKILL.md
Frappe Logging & Error Tracking
Three Logging Mechanisms
| Mechanism | Storage | Use For |
|---|---|---|
frappe.logger() |
File (rotating) | Application logging, debug info, audit trails |
frappe.log_error() |
Database (Error Log DocType) | Errors visible in admin UI, persistent tracking |
frappe.log() / frappe.errprint() |
stderr / request-scoped | Quick debugging only (NOT for production) |
Decision Tree
Need to log something?
│
├─ Application logging (info, debug, warnings)?
│ └─ frappe.logger("my_module").info("message")
│ → Writes to sites/{site}/logs/my_module.log
│
├─ Error that admins should see in Desk UI?
│ └─ frappe.log_error(title="Short desc", message=traceback)
│ → Creates Error Log document (queryable, auto-cleanup)
│
├─ Quick debug during development?
│ └─ frappe.errprint(variable) — shows in console
│ → NEVER leave in production code
│
├─ Track all HTTP requests?
│ └─ Set enable_frappe_logger: true in site_config.json
│ → Logs to frappe.web.log
│
├─ Performance monitoring?
│ └─ Set monitor: true in site_config.json
│ → Logs to monitor.json.log (JSON, per-request metrics)
│
└─ External error tracking (Sentry)?
└─ Set FRAPPE_SENTRY_DSN environment variable
→ Auto-captures unhandled exceptions
Quick Reference: frappe.logger()
# Get a logger for your module (ALWAYS specify module name)
logger = frappe.logger("my_app")
# Standard Python logging levels
logger.debug("Detailed diagnostic info")
logger.info("Normal operations: processed 50 records")
logger.warning("Something unexpected but recoverable")
logger.error("Operation failed", exc_info=True)
logger.critical("System-level failure")
# Full signature
frappe.logger(
module=None, # Logger name + log filename
with_more_info=False, # Auto-log request form_dict
allow_site=True, # Log under site's logs/ directory
filter=None, # Custom logging.Filter
max_size=100_000, # Max bytes per log file (100KB default)
file_count=20 # Rotated files retained (20 default)
)
Log location: sites/{site}/logs/{module}.log
Rotation: RotatingFileHandler — 100KB per file, 20 backups (~2MB total per logger)
Default Log Levels
| Mode | Level | Effect |
|---|---|---|
Development (_dev_server) |
WARNING | Debug/info suppressed |
| Production | ERROR | Only errors and above |
# Change level dynamically
frappe.utils.logger.set_log_level("DEBUG")
Quick Reference: frappe.log_error()
# ALWAYS use keyword arguments (title/message can swap otherwise)
frappe.log_error(
title="Payment gateway timeout", # Short description (140 chars max)
message=frappe.get_traceback(), # Full error details
reference_doctype="Payment Entry", # Related DocType
reference_name="PE-00001" # Related document
)
# Minimal — auto-captures current traceback
try:
risky_operation()
except Exception:
frappe.log_error(title="Operation failed")
Error Log cleanup: Auto-deletes after 30 days. Manual: frappe.whitelist: clear_error_logs()
Auto-Captured Exceptions
Unhandled exceptions (HTTP 500+) are automatically logged to Error Log.
Excluded from auto-capture:
frappe.AuthenticationErrorfrappe.CSRFTokenErrorfrappe.SecurityExceptionfrappe.InReadOnlyMode
Production Configuration
site_config.json Keys
| Key | Value | Effect |
|---|---|---|
enable_frappe_logger |
true |
HTTP request logging → frappe.web.log |
logging |
2 |
Log all SQL queries (debug only!) |
monitor |
true |
Request/job metrics → monitor.json.log |
disable_error_snapshot |
true |
Disable auto-capture of exceptions |
Environment Variables
| Variable | Effect |
|---|---|
FRAPPE_STREAM_LOGGING=1 |
Log to stderr instead of files |
FRAPPE_SENTRY_DSN=<dsn> |
Enable Sentry error tracking |
ENABLE_SENTRY_DB_MONITORING |
Track SQL queries in Sentry |
SENTRY_TRACING_SAMPLE_RATE |
Performance tracing rate (0.0-1.0) |
Production Log Files
| File | Content |
|---|---|
logs/web.error.log |
HTTP errors (supervisor) |
logs/web.log |
Gunicorn stdout |
logs/worker.error.log |
Background job errors |
logs/frappe.log |
Default frappe logger |
logs/frappe.web.log |
HTTP request metadata |
logs/monitor.json.log |
Performance metrics (JSON) |
sites/{site}/logs/*.log |
Per-site application logs |
Anti-Patterns
| NEVER | ALWAYS | Why |
|---|---|---|
print("debug info") |
frappe.logger("mod").info(...) |
print() disappears in production |
frappe.log_error("info msg") |
frappe.logger().info(...) |
log_error creates Error Log docs, clutters admin UI |
frappe.logger() (no module) |
frappe.logger("my_module") |
No-module mixes with framework logs |
frappe.log_error(title, msg) positional |
frappe.log_error(title=t, message=m) |
Positional args can swap (known quirk) |
| Log passwords/tokens | Mask sensitive data | SiteContextFilter only masks form_dict |
frappe.log() in production |
frappe.logger() |
frappe.log() is debug-only, request-scoped |
Leave logging=2 in prod |
Only during debugging | Logs ALL SQL queries, massive I/O |
Version Differences
| Feature | v14 | v15+ |
|---|---|---|
frappe.logger() |
Yes | Yes |
frappe.log_error() |
Yes | + defer_insert kwarg |
| Error Log trace_id | -- | Added |
| Error Log metadata | -- | JSON request/job context |
| Error snapshots | File-based + scheduled collection | Direct DB insert |
| Sentry integration | Basic | Enhanced (DB monitoring, profiling) |
guess_exception_source() |
-- | Identifies which app caused error |
FRAPPE_STREAM_LOGGING |
Yes | Yes |
Reference Files
- Logger API & Patterns — frappe.logger() advanced usage
- Error Tracking — Error Log, Sentry, monitoring
Related skills