Add structured logging throughout the backend: - logging_config.py: Centralized logging configuration with colored output - main.py: Enhanced startup logging showing initialization progress - init_blockchain.py: Detailed blockchain initialization logging - services.py: Election creation logging Logging features: - Emoji prefixes for different log levels (INFO, DEBUG, ERROR, etc.) - Color-coded output for better visibility - Timestamp and module information - Exception stack traces on errors - Separate loggers for different modules This helps debug: - Backend startup sequence - Database initialization - Blockchain election recording - Service operations - Configuration issues
118 lines
4.3 KiB
Python
118 lines
4.3 KiB
Python
"""
|
|
Initialize blockchain with existing elections from database.
|
|
|
|
This module ensures that when the backend starts, all elections in the database
|
|
are recorded to the blockchain if they aren't already.
|
|
"""
|
|
|
|
import logging
|
|
from sqlalchemy.orm import Session
|
|
from . import models
|
|
from .blockchain_elections import elections_blockchain, record_election_to_blockchain
|
|
from datetime import datetime
|
|
import json
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def initialize_elections_blockchain(db: Session) -> None:
|
|
"""
|
|
Initialize the elections blockchain with all elections from database.
|
|
|
|
Called on backend startup to ensure all elections are immutably recorded.
|
|
Uses the elections_blockchain.blocks to check if an election is already recorded.
|
|
|
|
Args:
|
|
db: Database session
|
|
"""
|
|
logger.info("-" * 60)
|
|
logger.info("Blockchain Initialization Started")
|
|
logger.info("-" * 60)
|
|
|
|
try:
|
|
# Get all elections from database
|
|
elections = db.query(models.Election).all()
|
|
logger.info(f"Found {len(elections)} elections in database")
|
|
|
|
if not elections:
|
|
logger.warning("No elections to record to blockchain")
|
|
return
|
|
|
|
# Check which elections are already on blockchain
|
|
existing_election_ids = {block.election_id for block in elections_blockchain.blocks}
|
|
logger.info(f"Blockchain currently has {len(existing_election_ids)} elections")
|
|
|
|
# Record each election that isn't already on blockchain
|
|
recorded_count = 0
|
|
skipped_count = 0
|
|
|
|
for election in elections:
|
|
if election.id in existing_election_ids:
|
|
logger.debug(f" ⊘ Election {election.id} ({election.name}) already on blockchain")
|
|
skipped_count += 1
|
|
continue
|
|
|
|
try:
|
|
# Get candidates for this election
|
|
candidates = db.query(models.Candidate).filter(
|
|
models.Candidate.election_id == election.id
|
|
).all()
|
|
|
|
logger.debug(f" Recording election {election.id} with {len(candidates)} candidates")
|
|
|
|
candidates_data = [
|
|
{
|
|
"id": c.id,
|
|
"name": c.name,
|
|
"description": c.description or "",
|
|
"order": c.order or 0
|
|
}
|
|
for c in candidates
|
|
]
|
|
|
|
# Record to blockchain
|
|
block = record_election_to_blockchain(
|
|
election_id=election.id,
|
|
election_name=election.name,
|
|
election_description=election.description or "",
|
|
candidates=candidates_data,
|
|
start_date=election.start_date.isoformat(),
|
|
end_date=election.end_date.isoformat(),
|
|
is_active=election.is_active,
|
|
creator_id=0 # Database creation, no specific admin
|
|
)
|
|
logger.info(
|
|
f" ✓ Recorded election {election.id} ({election.name})\n"
|
|
f" Block #{block.index}, Hash: {block.block_hash[:16]}..., "
|
|
f"Candidates: {block.candidates_count}"
|
|
)
|
|
recorded_count += 1
|
|
|
|
except Exception as e:
|
|
logger.error(
|
|
f" ✗ Failed to record election {election.id} ({election.name}): {e}",
|
|
exc_info=True
|
|
)
|
|
|
|
logger.info(f"Recording summary: {recorded_count} new, {skipped_count} skipped")
|
|
|
|
# Verify blockchain integrity
|
|
logger.info(f"Verifying blockchain integrity ({len(elections_blockchain.blocks)} blocks)...")
|
|
if elections_blockchain.verify_chain_integrity():
|
|
logger.info(f"✓ Blockchain integrity verified successfully")
|
|
else:
|
|
logger.error("✗ Blockchain integrity check FAILED - possible corruption!")
|
|
|
|
logger.info("-" * 60)
|
|
logger.info(f"Blockchain Initialization Complete")
|
|
logger.info(f" Total blocks: {len(elections_blockchain.blocks)}")
|
|
logger.info(f" Chain valid: {elections_blockchain.verify_chain_integrity()}")
|
|
logger.info("-" * 60)
|
|
|
|
except Exception as e:
|
|
logger.error(
|
|
f"Blockchain initialization failed with error: {e}",
|
|
exc_info=True
|
|
)
|
|
raise
|