Skip to content

Conversation

@MuncleUscles
Copy link
Member

@MuncleUscles MuncleUscles commented Jan 7, 2026

Summary

This PR implements a comprehensive logging policy to significantly reduce log volume (estimated ~80% reduction) while maintaining visibility for business events and errors.

Changes

New Files:

  • backend/protocol_rpc/logging_config.py - HealthCheckFilter to suppress /health access logs
  • backend/protocol_rpc/run_server.py - JSONRPC server entry point with logging config
  • backend/consensus/run_worker.py - Worker entry point with logging config
  • docs/LOGGING_POLICY.md - Logging guidelines documentation

Log Level Changes:

  • Health check access logs: Filtered out entirely (was ~62% of log volume)
  • Worker polling logs (_log_query_result): INFO → DEBUG (~21% of volume)
  • Claim operations (transaction, appeal, finalization): INFO → DEBUG
  • TX_PROCESSOR internal logs: INFO → DEBUG
  • TX_EXEC intermediate states: INFO → DEBUG
  • Recovery/appeal loop summaries: INFO → DEBUG

Kept at INFO (business events):

  • "Transaction finalized: {hash}"
  • "Successfully processed transaction {hash}"
  • Service startup/shutdown

Dockerfile Updates:

  • docker/Dockerfile.backend: Use run_server.py entry point
  • docker/Dockerfile.consensus-worker: Use run_worker.py entry point

Related Deployment Changes

The DISABLE_INFO_LOGS_ENDPOINTS config in devexp-apps-workload should be updated to include:

["ping", "gen_getTransactionStatus", "eth_getTransactionByHash", "eth_getTransactionReceipt", "eth_getTransactionCount", "gen_getContractSchemaForCode", "gen_getContractSchema", "eth_getCode", "eth_getBalance", "eth_call", "net_version", "eth_chainId", "sim_getTransactionsForAddress", "sim_getConsensusContract"]

Test plan

  • Build and run locally with docker compose up
  • Verify health check logs are filtered (check docker logs)
  • Verify worker logs no longer spam polling results
  • Verify transaction finalization still logs at INFO level
  • Test in dev environment before promoting to prod

Summary by CodeRabbit

  • New Features

    • Introduced configurable service logging with health-check access-log filtering and a distinct "not found" JSON‑RPC error type.
  • Documentation

    • Added a centralized logging policy covering levels, filtering, and logging guidance.
  • Chores

    • Service startup now applies the unified logging configuration.
    • Reduced routine log noise by moving many info logs to debug and set RPC endpoints to use a debug logging policy.

✏️ Tip: You can customize this high-level summary in your review settings.

- Add HealthCheckFilter to filter /health access logs (62% reduction)
- Downgrade worker polling/claim logs to DEBUG level
- Downgrade consensus intermediate state logs to DEBUG level
- Keep business events (tx finalized, tx processed) at INFO level
- Add run_server.py and run_worker.py entry points for uvicorn logging
- Update Dockerfiles to use new entry points
- Add LOGGING_POLICY.md documentation for logging guidelines

Key changes:
- Health check access logs now filtered in uvicorn config
- _log_query_result in worker.py changed to DEBUG
- Claim operations (tx, appeal, finalization) changed to DEBUG
- TX_PROCESSOR internal logs changed to DEBUG
- TX_EXEC intermediate states changed to DEBUG
- Recovery and appeal loop summaries changed to DEBUG

Expected log volume reduction: ~80% with these changes combined
with updated DISABLE_INFO_LOGS_ENDPOINTS in deployment configs.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 7, 2026

📝 Walkthrough

Walkthrough

Adds a centralized uvicorn logging configuration with a HealthCheckFilter, new Python entrypoints to start server and worker (applying that config), lowers routine consensus/worker log levels to DEBUG, introduces a JSON-RPC NotFoundError and per-endpoint LogPolicy with many RPC methods set to DEBUG, updates Docker CMDs, and adds logging policy docs. ( Forty-nine words )

Changes

Cohort / File(s) Summary
Uvicorn logging config & entrypoints
backend/protocol_rpc/logging_config.py, backend/protocol_rpc/run_server.py, backend/consensus/run_worker.py, asgi.py
New module provides HealthCheckFilter and get_uvicorn_log_config(); new run_server.py and run_worker.py entrypoints prepend /app to sys.path, read env vars, and start uvicorn with log_config=get_uvicorn_log_config(); asgi.py imports and uses the log config.
Consensus & worker logging
backend/consensus/base.py, backend/consensus/worker.py
Downgraded many routine INFO logs to DEBUG across polling/claiming/processing paths and periodic messages; control flow and APIs unchanged.
RPC error types & message handling
backend/protocol_rpc/exceptions.py, backend/protocol_rpc/endpoints.py, backend/protocol_rpc/message_handler/base.py, backend/protocol_rpc/message_handler/fastapi_handler.py
Added NotFoundError(JSONRPCError); endpoints now raise NotFoundError for not-found cases; message handler treats it as DEBUG/endpoint_not_found and suppresses tracebacks; fastapi handler now explicitly logs EventType.DEBUG.
RPC log policy & method registrations
backend/protocol_rpc/rpc_endpoint_manager.py, backend/protocol_rpc/rpc_methods.py
Added LogPolicy dataclass with per-endpoint log_level; many RPC methods updated to @rpc.method(..., log_policy=LogPolicy.debug()), and logging uses policy log_level rather than a fixed INFO.
Docker entrypoints
docker/Dockerfile.backend, docker/Dockerfile.consensus-worker
CMDs changed to invoke new Python module entrypoints (e.g., python3 -m backend.protocol_rpc.run_server) so startup delegates uvicorn logging config to wrapper scripts.
Documentation
docs/LOGGING_POLICY.md
New logging policy describing levels, RPC filtering, access-log handling (health check filtering), and guidelines for adding logs.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Suggested labels

run-tests

Suggested reviewers

  • cristiam86
  • kstroobants

Poem

🐰 I nibbled logs from loud to slight,
Filtered pings so health-checks hide their light,
Debugs now whisper where Info used to sing,
Workers, servers — tuned and spring,
A carrot-hop for quieter night 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.42% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main objective of the changeset: implementing comprehensive logging improvements to reduce log volume across the backend services.
Description check ✅ Passed The description is comprehensive and well-structured, covering all key areas: changes to logging policies, affected files, log level modifications, deployment changes, and testing plan.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @backend/protocol_rpc/logging_config.py:
- Around line 31-41: The function configure_uvicorn_logging is defined but never
used; either remove it to eliminate dead code or retain it with a clear
doc/comment explaining when it should be invoked; if keeping, add a note
referencing HealthCheckFilter and the "uvicorn.access" logger stating it must be
called before starting uvicorn (e.g., in server bootstrap) so readers know its
intended usage, otherwise delete the configure_uvicorn_logging function and any
unused HealthCheckFilter import/definition if not used elsewhere.
🧹 Nitpick comments (6)
asgi.py (1)

12-14: Clarify the comment about logging configuration.

The comment "Configure logging before importing the app" is misleading. Line 13 imports the get_uvicorn_log_config function but doesn't actually configure logging—that happens at line 36 when the function is called and passed to uvicorn.run(log_config=...).

Consider revising to:

# Import logging configuration for uvicorn
from backend.protocol_rpc.logging_config import get_uvicorn_log_config

If there's a specific reason this import must occur before the app import (e.g., side effects), please document that reason explicitly.

backend/protocol_rpc/run_server.py (2)

10-11: Hardcoded /app path reduces portability.

This assumes execution only from Docker. Consider deriving the path dynamically for local development:

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))

Or use a fallback that checks if /app exists.


16-30: Add return type annotation.

Per coding guidelines, include type hints in all Python code:

-def main():
+def main() -> None:
backend/consensus/run_worker.py (1)

16-28: Add return type annotation for consistency.

Same as run_server.py, add type hint per coding guidelines:

-def main():
+def main() -> None:
backend/protocol_rpc/logging_config.py (2)

14-15: Annotate class-level mutable attribute with ClassVar.

Per Ruff RUF012, mutable class attributes should be annotated:

+from typing import ClassVar
+
 class HealthCheckFilter(logging.Filter):
     """Filter out health check requests from access logs."""

     # Endpoints to filter (no logging for these paths)
-    FILTERED_PATHS = {"/health", "/ready", "/status"}
+    FILTERED_PATHS: ClassVar[set[str]] = {"/health", "/ready", "/status"}

22-26: Consider handling paths with query strings.

The current pattern matching won't filter requests like /health?check=1 or /ready?timeout=5. While health probes typically don't use query strings, a more robust approach would handle this:

         for path in self.FILTERED_PATHS:
             # Match patterns like: GET /health HTTP/1.1
-            if f'"{path} ' in message or f" {path} " in message:
+            if f'"{path} ' in message or f" {path} " in message or f'"{path}?' in message or f" {path}?" in message:
                 return False

Alternatively, use regex for cleaner matching.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a5436d1 and da6c3e1.

📒 Files selected for processing (9)
  • asgi.py
  • backend/consensus/base.py
  • backend/consensus/run_worker.py
  • backend/consensus/worker.py
  • backend/protocol_rpc/logging_config.py
  • backend/protocol_rpc/run_server.py
  • docker/Dockerfile.backend
  • docker/Dockerfile.consensus-worker
  • docs/LOGGING_POLICY.md
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Target Python 3.12, use 4-space indentation, and rely on Black via pre-commit for formatting consistency

**/*.py: Apply Black formatter for Python code formatting
Include type hints in all Python code

Files:

  • asgi.py
  • backend/protocol_rpc/logging_config.py
  • backend/consensus/base.py
  • backend/consensus/worker.py
  • backend/protocol_rpc/run_server.py
  • backend/consensus/run_worker.py
backend/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Align backend filenames with their behavior (e.g., validators/llm_validator.py) and mirror that pattern in tests

Files:

  • backend/protocol_rpc/logging_config.py
  • backend/consensus/base.py
  • backend/consensus/worker.py
  • backend/protocol_rpc/run_server.py
  • backend/consensus/run_worker.py
backend/consensus/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Implement validator rotation using VRF (Verifiable Random Function) in the consensus system

Files:

  • backend/consensus/base.py
  • backend/consensus/worker.py
  • backend/consensus/run_worker.py
🧠 Learnings (2)
📚 Learning: 2025-12-04T13:40:47.132Z
Learnt from: CR
Repo: genlayerlabs/genlayer-studio PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-04T13:40:47.132Z
Learning: Applies to backend/{asgi.py,uvicorn_config.py} : FastAPI backend bootstraps in `asgi.py` and `uvicorn_config.py`

Applied to files:

  • docker/Dockerfile.backend
  • asgi.py
  • backend/protocol_rpc/run_server.py
📚 Learning: 2025-09-08T16:24:56.379Z
Learnt from: cgmello
Repo: genlayerlabs/genlayer-studio PR: 1310
File: vector.yaml:17-18
Timestamp: 2025-09-08T16:24:56.379Z
Learning: The GenLayer Studio logging architecture uses GCP Stackdriver Logs and GCP Pub/Sub as sinks, where top-level fields like .host work well for filtering, rather than Loki-style labels.

Applied to files:

  • docs/LOGGING_POLICY.md
🧬 Code graph analysis (5)
asgi.py (1)
backend/protocol_rpc/logging_config.py (1)
  • get_uvicorn_log_config (44-101)
backend/consensus/base.py (2)
backend/node/genvm/origin/logger.py (1)
  • debug (14-15)
examples/contracts/_hello_world.py (1)
  • debug (34-38)
backend/consensus/worker.py (1)
backend/node/genvm/origin/logger.py (1)
  • debug (14-15)
backend/protocol_rpc/run_server.py (2)
backend/protocol_rpc/logging_config.py (1)
  • get_uvicorn_log_config (44-101)
backend/consensus/run_worker.py (1)
  • main (16-28)
backend/consensus/run_worker.py (3)
backend/protocol_rpc/logging_config.py (1)
  • get_uvicorn_log_config (44-101)
backend/protocol_rpc/run_server.py (1)
  • main (16-30)
backend/consensus/worker.py (1)
  • run (1056-1150)
🪛 Ruff (0.14.10)
backend/protocol_rpc/logging_config.py

15-15: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

backend/protocol_rpc/run_server.py

25-25: Possible binding to all interfaces

(S104)

backend/consensus/run_worker.py

24-24: Possible binding to all interfaces

(S104)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test
  • GitHub Check: load-test
  • GitHub Check: backend-unit-tests
🔇 Additional comments (14)
backend/consensus/base.py (4)

525-525: LGTM: Recovery loop logging appropriately downgraded to DEBUG.

The crawl_snapshot recovery loop logs (start, periodic summaries, stop) are internal housekeeping operations that don't require INFO-level visibility in production.

Also applies to: 638-645, 657-659


741-741: LGTM: Transaction processor internal logs appropriately downgraded to DEBUG.

Internal lifecycle events (starting loops, activating transactions, spawning processors, cleanup) are moved to DEBUG while preserving INFO-level logs for actual business outcomes (lines 887, 1140: "Successfully processed transaction"). This maintains visibility of critical events while reducing log noise.

Also applies to: 760-762, 848-850, 854-856, 874-876, 904-906, 933-938, 945-948, 986-988


1029-1031: LGTM: Transaction execution intermediate states appropriately downgraded to DEBUG.

Starting and intermediate execution steps are internal details, while the final success message at line 1140 remains at INFO level for visibility of completed transactions.

Also applies to: 1111-1113


1468-1468: LGTM: Appeal window loop logging appropriately downgraded to DEBUG.

The appeal window loop lifecycle logs (start, periodic summaries, stop) are internal operations that don't require INFO-level visibility. Critical appeal outcomes are handled elsewhere at appropriate log levels.

Also applies to: 1641-1645, 1654-1656

backend/consensus/worker.py (3)

188-190: LGTM: Claim operations appropriately downgraded to DEBUG.

Internal claim operations are internal state transitions that occur frequently during polling. Business outcomes (successful processing, finalization) remain at INFO level at lines 632, 893, 909.

Also applies to: 395-395


1029-1054: LGTM: Query result logging with clear documentation.

The docstring at line 1037 clearly explains the DEBUG-level intent for internal polling operations, and the implementation at line 1049 correctly uses DEBUG level for query results. The low-frequency logging pattern (60-second intervals) further reduces noise.


1083-1085: LGTM: Run loop claim operations appropriately downgraded to DEBUG.

Consistent with other claim operations in the file. These internal polling results are moved to DEBUG while preserving INFO-level logs for actual processing outcomes (lines 1009-1011: "Successfully processed appeal").

Also applies to: 1134-1136

asgi.py (1)

36-36: LGTM: Logging configuration correctly applied.

Replacing access_log=True with log_config=get_uvicorn_log_config() properly delegates logging configuration to the centralized logging module, enabling health check filtering and environment-driven log levels.

docker/Dockerfile.backend (1)

96-97: LGTM: Entrypoint correctly updated to use new logging-aware server script.

The change from direct uvicorn invocation to python3 -m backend.protocol_rpc.run_server properly delegates startup to the new entrypoint script that configures uvicorn logging, including health check filtering and environment-driven log levels.

docker/Dockerfile.consensus-worker (1)

113-116: LGTM: Worker entrypoint correctly updated to use new logging-aware script.

The change from direct uvicorn invocation to python3 -m backend.consensus.run_worker properly delegates startup to the new worker entrypoint script that configures uvicorn logging, mirroring the approach used in the backend Dockerfile.

backend/consensus/run_worker.py (1)

1-32: LGTM - consistent structure with run_server.py.

The entry point correctly configures uvicorn with the centralized logging config. The absence of a workers parameter (unlike run_server.py) is appropriate since consensus workers shouldn't scale horizontally within the same container.

docs/LOGGING_POLICY.md (2)

1-193: Well-structured logging policy.

The document provides clear, actionable guidance with good examples. The decision framework (lines 128-145) for adding new logs is particularly useful. This will help maintain consistency across the codebase.


162-169: No issues found. The documentation accurately reflects the implementation. The worker maintains separate poll_interval (5 seconds) and _query_log_interval (60 seconds) values, making the documented claim "logged every 60s, not per-poll" correct. Query polling results are intentionally sampled at 60-second intervals rather than logged on every 5-second poll cycle.

backend/protocol_rpc/logging_config.py (1)

44-101: LGTM - well-structured logging configuration.

The configuration correctly applies the health check filter to access logs while preserving standard logging for other requests. The separation of handlers (stderr for errors, stdout for access) follows best practices for container environments.

Add NotFoundError exception class for expected "not found" responses.
These are valid query responses, not system failures.

Changes:
- Add NotFoundError class in exceptions.py (code -32001)
- Update endpoint decorator to log NotFoundError at DEBUG level
- Update fastapi_handler to handle EventType.DEBUG properly
- Change transaction not found errors to use NotFoundError

Before: "Transaction X not found" logged as ERROR
After: "Transaction X not found" logged as DEBUG

This prevents log noise from normal queries for non-existent transactions.
Consistent error handling for expected "not found" responses:
- Contract not found (deployer check, validation, send_raw_transaction)
- Block not found
- Contract name not found

These are logged at DEBUG level instead of ERROR since they're
valid query outcomes, not system failures.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/protocol_rpc/message_handler/base.py (1)

1-361: Critical: Black formatting check failed.

The pre-commit hook detected formatting issues in this file. Please run Black to apply the required formatting:

black backend/protocol_rpc/message_handler/base.py

Or apply all formatting fixes:

pre-commit run --all-files
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da6c3e1 and 4c81b1a.

📒 Files selected for processing (5)
  • backend/protocol_rpc/endpoints.py
  • backend/protocol_rpc/exceptions.py
  • backend/protocol_rpc/message_handler/base.py
  • backend/protocol_rpc/message_handler/fastapi_handler.py
  • docs/LOGGING_POLICY.md
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Target Python 3.12, use 4-space indentation, and rely on Black via pre-commit for formatting consistency

**/*.py: Apply Black formatter for Python code formatting
Include type hints in all Python code

Files:

  • backend/protocol_rpc/exceptions.py
  • backend/protocol_rpc/message_handler/fastapi_handler.py
  • backend/protocol_rpc/message_handler/base.py
  • backend/protocol_rpc/endpoints.py
backend/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Align backend filenames with their behavior (e.g., validators/llm_validator.py) and mirror that pattern in tests

Files:

  • backend/protocol_rpc/exceptions.py
  • backend/protocol_rpc/message_handler/fastapi_handler.py
  • backend/protocol_rpc/message_handler/base.py
  • backend/protocol_rpc/endpoints.py
🧠 Learnings (1)
📚 Learning: 2025-09-08T16:24:56.379Z
Learnt from: cgmello
Repo: genlayerlabs/genlayer-studio PR: 1310
File: vector.yaml:17-18
Timestamp: 2025-09-08T16:24:56.379Z
Learning: The GenLayer Studio logging architecture uses GCP Stackdriver Logs and GCP Pub/Sub as sinks, where top-level fields like .host work well for filtering, rather than Loki-style labels.

Applied to files:

  • docs/LOGGING_POLICY.md
🧬 Code graph analysis (3)
backend/protocol_rpc/message_handler/fastapi_handler.py (2)
backend/protocol_rpc/message_handler/types.py (1)
  • EventType (5-10)
backend/node/genvm/origin/logger.py (1)
  • debug (14-15)
backend/protocol_rpc/message_handler/base.py (2)
backend/protocol_rpc/exceptions.py (2)
  • JSONRPCError (8-40)
  • NotFoundError (87-97)
backend/protocol_rpc/message_handler/types.py (3)
  • EventType (5-10)
  • LogEvent (21-41)
  • EventScope (13-17)
backend/protocol_rpc/endpoints.py (1)
backend/protocol_rpc/exceptions.py (2)
  • JSONRPCError (8-40)
  • NotFoundError (87-97)
🪛 GitHub Actions: pre-commit
backend/protocol_rpc/message_handler/base.py

[error] 1-1: Black formatting check failed. The hook reformatted 1 file (backend/protocol_rpc/message_handler/base.py) and exited with code 1. Run 'pre-commit run --all-files' to apply formatting locally.

🪛 Ruff (0.14.10)
backend/protocol_rpc/message_handler/base.py

277-277: Use explicit conversion flag

Replace with conversion flag

(RUF010)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: backend-unit-tests
🔇 Additional comments (5)
backend/protocol_rpc/endpoints.py (1)

8-8: LGTM! NotFoundError correctly replaces JSONRPCError for "not found" cases.

The introduction of NotFoundError for transaction lookup failures is appropriate. These are expected query outcomes (soft errors) that should be logged at DEBUG level rather than ERROR, reducing log noise from normal polling operations.

All three endpoints (get_transaction_by_hash, get_studio_transaction_by_hash, get_transaction_status) consistently use the new error type while preserving message format and data structure.

Also applies to: 1057-1060, 1074-1077, 1086-1089

backend/protocol_rpc/exceptions.py (1)

85-97: LGTM! Well-documented soft error for expected "not found" responses.

The NotFoundError class is well-designed with clear documentation explaining its purpose as a soft error for expected query outcomes. The error code -32001 appropriately sits in the application-specific range defined by the JSON-RPC specification.

docs/LOGGING_POLICY.md (1)

1-199: Excellent comprehensive logging policy documentation.

This policy document provides clear, actionable guidance for logging across the backend services. Key strengths:

  • Well-defined log levels with specific audiences and use cases
  • Concrete examples for each level
  • Clear distinction between final states (INFO) and intermediate states (DEBUG)
  • Explicit guidance on NotFoundError as a soft error at DEBUG level
  • Helpful decision tree for adding new logs

The document aligns well with the PR's goal of reducing log volume (~80%) while maintaining visibility for business events and errors.

backend/protocol_rpc/message_handler/fastapi_handler.py (1)

139-140: LGTM! Essential fix for DEBUG-level event handling.

Adding explicit handling for EventType.DEBUG ensures these events are logged at the debug level rather than falling through to the else branch where they would incorrectly be logged as INFO. This change is necessary to support the new logging policy's distinction between routine operations (DEBUG) and business events (INFO).

backend/protocol_rpc/message_handler/base.py (1)

12-12: LGTM! NotFoundError correctly treated as soft error.

The special handling for NotFoundError properly distinguishes expected query outcomes from actual system failures:

  • NotFoundError → logged at DEBUG level with event name "endpoint_not_found"
  • Other exceptions → logged at ERROR level with event name "endpoint_error"
  • Traceback included only for ERROR-level events (line 281)

This reduces log noise from normal polling operations that return "not found" responses.

Also applies to: 263-286

Previously DISABLE_INFO_LOGS_ENDPOINTS would completely skip logging.
Now these methods are logged at DEBUG level, making them available
for troubleshooting when LOG_LEVEL=debug while keeping production
logs clean.
Replace DISABLE_INFO_LOGS_ENDPOINTS env var with per-endpoint
log level configuration. Each endpoint now declares its log level
in the endpoint definition using LogPolicy.debug() for high-frequency
polling methods.

Benefits:
- Self-documenting: log level is visible in endpoint definition
- Type-safe: no JSON parsing from env vars
- Consistent: same behavior across all environments
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
backend/protocol_rpc/logging_config.py (1)

11-28: Annotate class attribute with ClassVar for type safety.

The FILTERED_PATHS class attribute should be annotated with typing.ClassVar[set[str]] to clarify that it's shared across all instances and not an instance attribute.

🔎 Proposed fix
+from typing import ClassVar
+
 class HealthCheckFilter(logging.Filter):
     """Filter out health check requests from access logs."""
 
     # Endpoints to filter (no logging for these paths)
-    FILTERED_PATHS = {"/health", "/ready", "/status"}
+    FILTERED_PATHS: ClassVar[set[str]] = {"/health", "/ready", "/status"}

Based on static analysis hints (Ruff RUF012).

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4c81b1a and b92cfac.

📒 Files selected for processing (6)
  • backend/protocol_rpc/endpoints.py
  • backend/protocol_rpc/logging_config.py
  • backend/protocol_rpc/message_handler/base.py
  • backend/protocol_rpc/rpc_endpoint_manager.py
  • backend/protocol_rpc/rpc_methods.py
  • docs/LOGGING_POLICY.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/LOGGING_POLICY.md
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Target Python 3.12, use 4-space indentation, and rely on Black via pre-commit for formatting consistency

**/*.py: Apply Black formatter for Python code formatting
Include type hints in all Python code

Files:

  • backend/protocol_rpc/rpc_endpoint_manager.py
  • backend/protocol_rpc/rpc_methods.py
  • backend/protocol_rpc/endpoints.py
  • backend/protocol_rpc/logging_config.py
  • backend/protocol_rpc/message_handler/base.py
backend/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Align backend filenames with their behavior (e.g., validators/llm_validator.py) and mirror that pattern in tests

Files:

  • backend/protocol_rpc/rpc_endpoint_manager.py
  • backend/protocol_rpc/rpc_methods.py
  • backend/protocol_rpc/endpoints.py
  • backend/protocol_rpc/logging_config.py
  • backend/protocol_rpc/message_handler/base.py
🧠 Learnings (4)
📚 Learning: 2025-09-03T15:21:09.877Z
Learnt from: epsjunior
Repo: genlayerlabs/genlayer-studio PR: 1302
File: backend/protocol_rpc/endpoints.py:431-438
Timestamp: 2025-09-03T15:21:09.877Z
Learning: ContractSnapshot class in backend/database_handler/contract_snapshot.py handles deployment validation by raising Exception("Contract {address} not found") for missing contracts and Exception("Contract {address} not deployed") for contracts with empty data, centralizing validation logic that was previously in RPC endpoints.

Applied to files:

  • backend/protocol_rpc/endpoints.py
📚 Learning: 2025-09-03T15:21:09.877Z
Learnt from: epsjunior
Repo: genlayerlabs/genlayer-studio PR: 1302
File: backend/protocol_rpc/endpoints.py:431-438
Timestamp: 2025-09-03T15:21:09.877Z
Learning: ContractSnapshot class in backend/database_handler/contract_snapshot.py handles deployment validation and raises appropriate exceptions for contracts that aren't deployed, eliminating the need for additional error handling in the RPC endpoints.

Applied to files:

  • backend/protocol_rpc/endpoints.py
📚 Learning: 2025-06-16T02:16:55.779Z
Learnt from: kstroobants
Repo: genlayerlabs/genlayer-studio PR: 1204
File: backend/database_handler/contract_processor.py:61-73
Timestamp: 2025-06-16T02:16:55.779Z
Learning: In the GenLayer Studio backend, when a contract transaction exists, endpoints.py ensures that an empty contract is created via accounts_manager.create_new_account_with_address(new_contract_address), so reset_contract() won't encounter NoResultFound exceptions.

Applied to files:

  • backend/protocol_rpc/endpoints.py
📚 Learning: 2025-06-16T02:16:55.779Z
Learnt from: kstroobants
Repo: genlayerlabs/genlayer-studio PR: 1204
File: backend/database_handler/contract_processor.py:61-73
Timestamp: 2025-06-16T02:16:55.779Z
Learning: In the GenLayer Studio backend, when a contract transaction exists, endpoint.py ensures that an empty contract is created via accounts_manager.create_new_account_with_address(new_contract_address), so reset_contract() won't encounter NoResultFound exceptions.

Applied to files:

  • backend/protocol_rpc/endpoints.py
🧬 Code graph analysis (4)
backend/protocol_rpc/rpc_endpoint_manager.py (2)
backend/protocol_rpc/message_handler/types.py (2)
  • EventType (5-10)
  • EventScope (13-17)
backend/protocol_rpc/rpc_decorators.py (1)
  • method (17-34)
backend/protocol_rpc/rpc_methods.py (2)
backend/protocol_rpc/rpc_endpoint_manager.py (2)
  • LogPolicy (58-76)
  • debug (74-76)
backend/protocol_rpc/rpc_decorators.py (1)
  • method (17-34)
backend/protocol_rpc/endpoints.py (1)
backend/protocol_rpc/exceptions.py (2)
  • JSONRPCError (8-40)
  • NotFoundError (87-97)
backend/protocol_rpc/message_handler/base.py (2)
backend/protocol_rpc/exceptions.py (2)
  • JSONRPCError (8-40)
  • NotFoundError (87-97)
backend/protocol_rpc/message_handler/types.py (3)
  • EventType (5-10)
  • LogEvent (21-41)
  • EventScope (13-17)
🪛 Ruff (0.14.10)
backend/protocol_rpc/endpoints.py

558-561: Abstract raise to an inner function

(TRY301)

backend/protocol_rpc/logging_config.py

15-15: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

backend/protocol_rpc/message_handler/base.py

277-277: Use explicit conversion flag

Replace with conversion flag

(RUF010)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: backend-unit-tests
🔇 Additional comments (10)
backend/protocol_rpc/logging_config.py (1)

31-88: LGTM! Well-structured uvicorn logging configuration.

The logging configuration properly integrates the health check filter with uvicorn's access logger and follows uvicorn's expected dictionary configuration format.

backend/protocol_rpc/rpc_endpoint_manager.py (3)

57-76: LGTM! Clean per-endpoint logging policy design.

The LogPolicy dataclass with a debug() classmethod provides a clear, type-safe way to configure logging levels per endpoint. The design aligns well with the PR's goal to reduce log volume for high-frequency methods.


175-218: LGTM! Per-endpoint log levels properly applied.

The logging calls now correctly use definition.log_policy.log_level instead of fixed EventType.INFO, enabling per-endpoint control over request and success log verbosity while keeping errors at ERROR level.


407-409: LGTM! Simplified logging control.

Removing the dependency on GlobalConfiguration and relying solely on per-endpoint LogPolicy flags is cleaner and more maintainable.

backend/protocol_rpc/rpc_methods.py (1)

27-27: LGTM! Appropriate endpoints demoted to DEBUG level.

The selected endpoints (ping, balance/transaction/schema getters, and Ethereum-compatible read methods) are well-chosen for DEBUG-level logging. These are high-frequency, low-impact operations that would otherwise dominate INFO logs.

Also applies to: 35-35, 248-248, 276-276, 321-321, 336-336, 413-413, 426-426, 452-452, 463-463, 507-507, 520-520, 525-525, 562-562

backend/protocol_rpc/message_handler/base.py (1)

12-12: LGTM! Appropriate soft-error handling for NotFoundError.

The special handling for NotFoundError correctly treats it as an expected outcome (DEBUG level, endpoint_not_found event) rather than a system failure, and only includes tracebacks for actual ERROR-level events. This aligns well with the PR's goal to reduce noise in logs.

Also applies to: 263-290

backend/protocol_rpc/endpoints.py (4)

8-8: LGTM! Appropriate use of NotFoundError for missing contracts.

The replacement of JSONRPCError with NotFoundError for contract-not-found scenarios in admin_upgrade_contract_code is correct. These are expected query outcomes that should be logged at DEBUG level rather than ERROR.

Also applies to: 558-602


1055-1088: LGTM! Consistent NotFoundError usage for transaction queries.

The three transaction query endpoints (get_transaction_by_hash, get_studio_transaction_by_hash, get_transaction_status) correctly raise NotFoundError when transactions don't exist, treating these as expected outcomes rather than system errors.


1281-1284: LGTM! NotFoundError for missing contract target.

Raising NotFoundError when the target contract doesn't exist during send_raw_transaction is appropriate, as this is a validation failure rather than an internal system error.


1401-1404: LGTM! NotFoundError for block and consensus contract queries.

Both get_block_by_number and get_contract (consensus service) correctly use NotFoundError for missing resources, treating these as normal query outcomes rather than errors requiring investigation.

Also applies to: 1535-1538

@sonarqubecloud
Copy link

sonarqubecloud bot commented Jan 7, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
22.7% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@cristiam86 cristiam86 merged commit 02430ac into main Jan 7, 2026
26 of 28 checks passed
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

🎉 This PR is included in version 0.87.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants