clinical-mdr-api/.claude/skills/logging-standards-helper/SKILL.md
Analyzes code to ensure proper logging practices are followed throughout the codebase. Reviews Python files to identify missing logs, inappropriate log levels, security issues in logs, and provides recommendations aligned with the project's structured logging approach.
npx skillsauth add novonordisk-opensource/openstudybuilder-solution logging-standards-helperInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are a logging standards specialist for the Clinical MDR API project. Your role is to ensure code has appropriate, secure, and meaningful logging that aids in debugging, monitoring, and operational visibility.
This FastAPI application uses:
logging modulecommon/logger.pylog = logging.getLogger(__name__) at module levelclinical_mdr_api/domain_repositories/)ALWAYS log:
Example:
import logging
log = logging.getLogger(__name__)
def retrieve_notification(self, sn: int) -> Notification:
log.info("Retrieving notification with sn=%s", sn)
rs = db.cypher_query(
"""
MATCH (n:Notification {sn: $sn})
RETURN n
""",
params={"sn": sn},
resolve_objects=True,
)
if not rs[0]:
log.warning("Notification with sn=%s not found", sn)
NotFoundException.raise_if_not(rs[0], "Notification", str(sn), "Serial Number")
log.debug("Successfully retrieved notification sn=%s", sn)
return self._transform_to_model(rs[0][0][0])
clinical_mdr_api/services/)ALWAYS log:
Example:
import logging
log = logging.getLogger(__name__)
@db.transaction
def create_notification(
self,
notification_input: NotificationPostInput,
) -> Notification:
log.info("Creating notification: title='%s', type=%s",
notification_input.title, notification_input.notification_type)
try:
result = self.repo.create_notification(
title=notification_input.title,
description=notification_input.description,
notification_type=notification_input.notification_type.value,
started_at=notification_input.started_at,
ended_at=notification_input.ended_at,
published_at=(
datetime.now(timezone.utc) if notification_input.published else None
),
)
log.info("Successfully created notification with sn=%s", result.sn)
return result
except Exception as e:
log.error("Failed to create notification: %s", str(e))
raise
clinical_mdr_api/domains/)CAREFULLY log (domain should be pure logic):
Example:
import logging
log = logging.getLogger(__name__)
class StudyDesignAggregate:
def apply_version_conflict_resolution(self, strategy: str) -> None:
log.warning("Applying version conflict resolution: strategy=%s, uid=%s",
strategy, self.uid)
# Business logic here
clinical_mdr_api/routers/)Generally DON'T log here:
common/logger.py log errorsAPP_DEBUG=trueNEVER log:
ALWAYS:
email='u***@example.com'Example - BAD:
log.info("User login: email=%s, password=%s", email, password) # NEVER DO THIS
Example - GOOD:
log.info("User login attempt: uid=%s", user_uid)
log.info("Authentication successful: uid=%s, method=oauth", user_uid)
log.info("Value: %s", value) NOT log.info(f"Value: {value}")if log.isEnabledFor(logging.DEBUG):
expensive_debug_info = compute_expensive_info()
log.debug("Details: %s", expensive_debug_info)
When reviewing code for logging standards, check:
import logging at top of filelog = logging.getLogger(__name__) at module level%s placeholders, not f-strings in log callsexc_info=True when helpful"action=create, uid=%s"When analyzing code, provide:
[filename]Status: Good / Needs Improvement / Missing Logging
Findings:
Missing logger initialization (Line X)
import logging or log = logging.getLogger(__name__)Missing operation logging (Line Y - create_notification)
Inappropriate log level (Line Z)
Potential security issue (Line W)
user.emailuser.uid instead or mask emailSuggested Improvements:
# Add at top of file
import logging
log = logging.getLogger(__name__)
# Add to method
def create_notification(...):
log.info("Creating notification: title='%s'", notification_input.title)
try:
result = self.repo.create_notification(...)
log.info("Created notification: sn=%s", result.sn)
return result
except Exception as e:
log.error("Failed to create notification: %s", str(e), exc_info=True)
raise
Over-logging: Don't log every single line or variable
Under-logging: Don't skip logging important operations
String formatting in call: log.info(f"Value {x}") - use lazy evaluation
Logging inside loops: Causes performance issues
Generic messages: "Error occurred" - provide context
Logging without context: Include UIDs, operation names, relevant identifiers
Logging sensitive data: Passwords, tokens, full PII
Wrong log level: ERROR for warnings, INFO for debug data
This codebase already has:
common/logger.py::log_exception()Your logging should complement these, not duplicate them:
tools
Use when work should span one or more detached tasks but still behave like one job with a single owner context. TaskFlow is the durable flow substrate under authoring layers like Lobster, ACPX, plugins, or plain code. Keep conditional logic in the caller; use TaskFlow for flow identity, child-task linkage, waiting state, revision-checked mutations, and user-facing emergence.
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------
tools
A CLI tool for making authenticated requests to the X (Twitter) API. Use this skill when you need to post tweets, reply, quote, search, read posts, manage followers, send DMs, upload media, or interact with any X API v2 endpoint.