refactor: migrate all remaining logging to structured_log, remove boilerplate helpers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
19ca53186c
commit
db0ac6a228
27 changed files with 361 additions and 913 deletions
|
|
@ -10,6 +10,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|||
from sqlalchemy.orm import aliased
|
||||
|
||||
from app.db.models import Publication, PublicationIdentifier, ScholarPublication
|
||||
from app.logging_utils import structured_log
|
||||
from app.services.domains.ingestion.fingerprints import (
|
||||
canonical_title_text_for_dedup,
|
||||
canonical_title_tokens_for_dedup,
|
||||
|
|
@ -104,14 +105,7 @@ async def merge_duplicate_publication(
|
|||
await _migrate_scholar_links(db_session, winner_id=winner_id, dup_id=dup_id)
|
||||
await _migrate_identifiers(db_session, winner_id=winner_id, dup_id=dup_id)
|
||||
await db_session.execute(delete(Publication).where(Publication.id == dup_id))
|
||||
logger.info(
|
||||
"publications.identifier_merge",
|
||||
extra={
|
||||
"event": "publications.identifier_merge",
|
||||
"winner_id": winner_id,
|
||||
"dup_id": dup_id,
|
||||
},
|
||||
)
|
||||
structured_log(logger, "info", "publications.identifier_merge", winner_id=winner_id, dup_id=dup_id)
|
||||
|
||||
|
||||
async def _load_publication(
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from app.services.domains.publications.pdf_queue import (
|
|||
enqueue_retry_pdf_job,
|
||||
overlay_pdf_job_state,
|
||||
)
|
||||
from app.logging_utils import structured_log
|
||||
from app.services.domains.publications.types import PublicationListItem
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -29,14 +30,7 @@ async def schedule_missing_pdf_enrichment_for_user(
|
|||
rows=items,
|
||||
max_items=max_items,
|
||||
)
|
||||
logger.info(
|
||||
"publications.enrichment.scheduled",
|
||||
extra={
|
||||
"event": "publications.enrichment.scheduled",
|
||||
"user_id": user_id,
|
||||
"publication_count": len(queued_ids),
|
||||
},
|
||||
)
|
||||
structured_log(logger, "info", "publications.enrichment.scheduled", user_id=user_id, publication_count=len(queued_ids))
|
||||
return len(queued_ids)
|
||||
|
||||
|
||||
|
|
@ -53,15 +47,7 @@ async def schedule_retry_pdf_enrichment_for_row(
|
|||
request_email=request_email,
|
||||
row=item,
|
||||
)
|
||||
logger.info(
|
||||
"publications.enrichment.retry_scheduled",
|
||||
extra={
|
||||
"event": "publications.enrichment.retry_scheduled",
|
||||
"user_id": user_id,
|
||||
"publication_id": item.publication_id,
|
||||
"queued": queued,
|
||||
},
|
||||
)
|
||||
structured_log(logger, "info", "publications.enrichment.retry_scheduled", user_id=user_id, publication_id=item.publication_id, queued=queued)
|
||||
return queued
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ from app.services.domains.unpaywall.application import (
|
|||
FAILURE_RESOLUTION_EXCEPTION,
|
||||
OaResolutionOutcome,
|
||||
)
|
||||
from app.logging_utils import structured_log
|
||||
from app.settings import settings
|
||||
|
||||
PDF_STATUS_UNTRACKED = "untracked"
|
||||
|
|
@ -320,10 +321,7 @@ def _drop_finished_task(task: asyncio.Task[None]) -> None:
|
|||
try:
|
||||
task.result()
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"publications.pdf_queue.task_failed",
|
||||
extra={"event": "publications.pdf_queue.task_failed"},
|
||||
)
|
||||
logger.exception("publications.pdf_queue.task_failed")
|
||||
|
||||
|
||||
async def _mark_attempt_started(
|
||||
|
|
@ -474,14 +472,7 @@ async def _resolve_publication_row(
|
|||
# Propagate upward so the batch loop can stop immediately.
|
||||
raise
|
||||
except Exception as exc: # pragma: no cover - defensive network boundary
|
||||
logger.warning(
|
||||
"publications.pdf_queue.resolve_failed",
|
||||
extra={
|
||||
"event": "publications.pdf_queue.resolve_failed",
|
||||
"publication_id": row.publication_id,
|
||||
"error": str(exc),
|
||||
},
|
||||
)
|
||||
structured_log(logger, "warning", "publications.pdf_queue.resolve_failed", publication_id=row.publication_id, error=str(exc))
|
||||
outcome = _failed_outcome(row=row)
|
||||
arxiv_rate_limited = False
|
||||
await _persist_outcome(
|
||||
|
|
@ -523,19 +514,9 @@ async def _run_resolution_task(
|
|||
)
|
||||
if arxiv_rate_limited and arxiv_lookup_allowed:
|
||||
arxiv_lookup_allowed = False
|
||||
logger.warning(
|
||||
"publications.pdf_queue.arxiv_batch_disabled",
|
||||
extra={
|
||||
"event": "publications.pdf_queue.arxiv_batch_disabled",
|
||||
"detail": "arXiv temporarily disabled for remaining batch after rate limit",
|
||||
},
|
||||
)
|
||||
structured_log(logger, "warning", "publications.pdf_queue.arxiv_batch_disabled", detail="arXiv temporarily disabled for remaining batch after rate limit")
|
||||
except OpenAlexBudgetExhaustedError:
|
||||
logger.warning(
|
||||
"publications.pdf_queue.budget_exhausted",
|
||||
extra={"event": "publications.pdf_queue.budget_exhausted",
|
||||
"detail": "Stopping PDF resolution batch — OpenAlex daily budget exhausted"},
|
||||
)
|
||||
structured_log(logger, "warning", "publications.pdf_queue.budget_exhausted", detail="Stopping PDF resolution batch — OpenAlex daily budget exhausted")
|
||||
break
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from app.services.domains.arxiv.guards import arxiv_skip_reason_for_item
|
|||
from app.services.domains.openalex.client import OpenAlexBudgetExhaustedError
|
||||
from app.services.domains.publications.types import PublicationListItem
|
||||
from app.services.domains.unpaywall.application import OaResolutionOutcome, resolve_publication_oa_outcomes
|
||||
from app.logging_utils import structured_log
|
||||
from app.settings import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -44,13 +45,7 @@ async def resolve_publication_pdf_outcome_for_row(
|
|||
except ArxivRateLimitError:
|
||||
arxiv_rate_limited = True
|
||||
arxiv_outcome = None
|
||||
logger.warning(
|
||||
"publications.pdf_resolution.arxiv_rate_limited",
|
||||
extra={
|
||||
"event": "publications.pdf_resolution.arxiv_rate_limited",
|
||||
"publication_id": int(row.publication_id),
|
||||
},
|
||||
)
|
||||
structured_log(logger, "warning", "publications.pdf_resolution.arxiv_rate_limited", publication_id=int(row.publication_id))
|
||||
if arxiv_outcome and arxiv_outcome.pdf_url:
|
||||
return PipelineOutcome(arxiv_outcome, None, arxiv_rate_limited=arxiv_rate_limited)
|
||||
|
||||
|
|
@ -99,10 +94,7 @@ async def _openalex_outcome(
|
|||
# Re-raise so the caller's batch loop can stop hitting the API.
|
||||
raise
|
||||
except Exception as exc:
|
||||
logger.warning(
|
||||
"publications.pdf_resolution.openalex_failed",
|
||||
extra={"event": "publications.pdf_resolution.openalex_failed", "error": str(exc)},
|
||||
)
|
||||
structured_log(logger, "warning", "publications.pdf_resolution.openalex_failed", error=str(exc))
|
||||
return None
|
||||
|
||||
|
||||
|
|
@ -115,12 +107,12 @@ async def _arxiv_outcome(
|
|||
from app.services.domains.arxiv.application import discover_arxiv_id_for_publication
|
||||
|
||||
if not allow_lookup:
|
||||
_log_arxiv_skip(row=row, skip_reason="batch_arxiv_cooldown_active")
|
||||
structured_log(logger, "info", "publications.pdf_resolution.arxiv_skipped", publication_id=int(row.publication_id), skip_reason="batch_arxiv_cooldown_active")
|
||||
return None
|
||||
|
||||
skip_reason = arxiv_skip_reason_for_item(item=row)
|
||||
if skip_reason is not None:
|
||||
_log_arxiv_skip(row=row, skip_reason=skip_reason)
|
||||
structured_log(logger, "info", "publications.pdf_resolution.arxiv_skipped", publication_id=int(row.publication_id), skip_reason=skip_reason)
|
||||
return None
|
||||
|
||||
try:
|
||||
|
|
@ -138,23 +130,10 @@ async def _arxiv_outcome(
|
|||
except ArxivRateLimitError:
|
||||
raise # propagate so orchestration can switch to non-arXiv fallback
|
||||
except Exception as exc:
|
||||
logger.warning(
|
||||
"publications.pdf_resolution.arxiv_failed",
|
||||
extra={"event": "publications.pdf_resolution.arxiv_failed", "error": str(exc)},
|
||||
)
|
||||
structured_log(logger, "warning", "publications.pdf_resolution.arxiv_failed", error=str(exc))
|
||||
return None
|
||||
|
||||
|
||||
def _log_arxiv_skip(*, row: PublicationListItem, skip_reason: str) -> None:
|
||||
logger.info(
|
||||
"publications.pdf_resolution.arxiv_skipped",
|
||||
extra={
|
||||
"event": "publications.pdf_resolution.arxiv_skipped",
|
||||
"publication_id": int(row.publication_id),
|
||||
"skip_reason": skip_reason,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
async def _oa_outcome(
|
||||
*,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue