본문으로 건너뛰기
cccskills
무료GitHub에 공개

logging

Structured logging conventions for DraftForge backend (Django/Celery/Daphne) and frontend (React). This skill should be used when adding log statements, creating new modules, debugging with logs, or reviewing logging patterns. Covers structlog usage, system/subsystem taxonomy, required fields, log levels, and Grafana query patterns.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

연동 도구Discord
설치 방법 보기

포함된 파일(4)

  • SKILL.md10.1 KB
  • references/backend.md3.6 KB
  • references/frontend.md2.3 KB
  • references/grafana-loki.md4.6 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Structured Logging

DraftForge uses structlog (backend) for structured JSON logging exported to Grafana Cloud via OpenTelemetry. All logs use a system/subsystem taxonomy for filtering.

Backend: Quick Start

from telemetry.logging import get_logger
log = get_logger(__name__)

# Structured log — event name first, then kwargs
log.info("order_created", system="tournament", subsystem="registration", draft_id=5, user_id=42)

Never use f-strings or % formatting in log messages. The first argument is always an event name (snake_case). All context goes in kwargs.

System / Subsystem Taxonomy

Every log MUST include system and subsystem kwargs. These are the primary Grafana filter dimensions.

Two-axis taxonomy: system / subsystem answer where the code lives (single value, label-friendly). tags: list[str] is an optional secondary axis answering what domains this log concerns (multi-value, for cross-cutting queries like "show me everything related to signups"). When tags are set, also set tags_csv (comma-joined string) for clean LogQL =~ filtering (Loki's | json flattens lists as tags_0, tags_1 which is awkward to filter). Bind tags via discord_log_context for interaction-flow logs, or pass explicitly for one-off cross-cutting logs.

systemsubsystemtagsWhereWhat
herodraftconnection—consumers.pyWS connect/disconnect, captain state, kicks
herodraftheartbeat—herodraft_tick.pyHeartbeat staleness checks, heartbeat-triggered pauses
herodrafttimer—herodraft_tick.pyTick loop lifecycle, tick broadcast, timeout auto-pick, resume
websocketheartbeat—consumers_base.pyHeartbeat receive, captain register/unregister (generic WS infra)
websocketconnection—telemetry/websocket.pyGeneric WS connect/disconnect/receive instrumentation
herodraftview—app/functions/herodraft_views.pyHeroDraft HTTP actions: create, roll, choice/pick submit, abandon, reset
celerytask—telemetry/celery.pyGeneric Celery task lifecycle bookends (started/completed/failed)
eventsdiscord—events/tasks.py (cron sync, non-interaction tasks like sync_discord_events)Cron-driven event sync to Discord that isn't triggered by an interaction
eventsscheduling—events/tasks.pyEvent generation, signup opening, repeaters
tournamentdiscord—discordbot/tasks.pyTournament DMs, bracket notifications
avatarsendpoint—user/internal/avatar.pyInternal endpoints: list-linked-users, list-guild-ids, bulk-update + invalidate
avatarsrefresh—app/tasks/avatar_refresh.py::refresh_avatars_batchedDaily Celery beat: read guild-member cache, diff against DB, POST bulk-update
avatarssingle—app/tasks/avatar_refresh.py::refresh_single_user_avatar + helpersSingle-user refresh: Discord API fetch + per-user update_user_avatar
avatarslegacy—app/tasks/avatar_refresh.py::refresh_discord_avatars / refresh_all_discord_dataOlder per-user fanout tasks (predates the batched path)
discordlease—discordbot/tasks.py, app/views/internal.pyDiscordMessageLog stale-lease sweep (pending NULL >5min, failed >1h)
discordinteraction["events","signup"]discordbot/components.py, discordbot/signup_responses.py, discordbot/log_context.pyDiscord-bot UI plumbing + response delivery: button/modal/select callbacks
discorddispatch["events","signup"]events/discord/dispatch.pynotify_* dispatch visibility (queued vs skipped); threads interaction_id to Celery
discordcelery["events","signup"]events/tasks.py (Discord-dispatching tasks)celery_task_started/finished/failed bookend logs
cacheinvalidate—app/cache_utils.pyPer-object cacheops invalidation fired from transaction.on_commit
websocketbroadcast—app/broadcast.pyDraft / herodraft event + state broadcast to channel groups (kind field distinguishes draft/herodraft/herodraft_state)
authinternal—app/auth.pyInternal-service auth (X-Internal-Token): IP-allowlist rejects, invalid-token failures
authsocial—app/pipelines.pyDiscord OAuth social-auth pipeline: account reclaim/merge, username matching
authmerge—app/discord_accounts.pyDiscord account de-dup / merge
tournamentdraft, registration, user—app/models.py, app/functions/tournament.pyDraft build/pick/rebuild, captain/team registration, per-user avatar refresh
apiserializer, routing, main, csv_import, joke—app/serializers.py, app/views*.py, app/views/csv_import.py, backend/urls.pyDRF serializer mutations, view cache-miss, CSV import, env/routing
userfunctions—app/functions/user.pyProfile-update request/validate/apply
appsignals—app/signals.pyModel signal handlers (org/league user create, herodraft cleanup)
internal_clienthttp—app/internal_client/__init__.pyInternal HTTP client JSON-parse failures
discordbot, utils, views, channels, roles, users—discordbot/**Bot lifecycle, message utils, slash views, channel/role/user services
eventstasks, services, views, dispatch—events/**Event task lifecycle, signup services, manual fire, tournament-link dispatch
steamapi, game_linking, match, mmr, stats, model, league_sync, retry—steam/**Steam API, account/game linking, match fetch/store, MMR/stats, league sync, retry
bracketgenerate, model—bracket/**Bracket generation + model-level cache logging
orgviews—org/views.pyOrg admin actions (user delete/merge)
commonutils—common/utils.pyShared utility warnings (CI/IP detection)

Add new systems/subsystems as features grow. Keep systems coarse (feature area), subsystems functional (what role the code plays).

Cross-System Correlation

Logs that span multiple systems carry an interaction_id (Discord interaction) or request_id (web request) so a single user action can be traced across processes.

For Discord interactions, the discord_log_context async CM in discordbot/log_context.py binds:

  • interaction_id — primary correlation key (Discord-generated, unique per click)
  • discord_user_id, discord_username, channel_id, guild_id
  • custom_id, event_id, interaction_type
  • tags=["events","signup"] (or other prefix-derived tags)
  • tags_csv="events,signup" (flat string for clean LogQL filtering)

These propagate via structlog.contextvars.merge_contextvars through await and sync_to_async. They also propagate across Celery .delay() calls when the dispatch site passes interaction_id as a kwarg and the task calls bind_contextvars(interaction_id=...) at entry.

OTel trace_id and span_id are injected automatically by the _add_otel_trace_context processor in telemetry/logging.py. At a 10% sample rate, the trace_id is in every log line for that 10%; for the other 90%, rely on interaction_id for log-side correlation.

Grafana query patterns

# Single user click
{service_name="backend"} | json | interaction_id="<id>"

# Cross-cutting: anything signup-related
{service_name="backend"} | json | tags_csv=~".*signup.*"

# Discord code that touches events
{service_name="backend"} | json | system="discord" | tags_csv=~".*events.*"

Log Levels

LevelWhenExported to Grafana?
DEBUGPer-request/per-tick detail, heartbeat receivedNo (prod=INFO)
INFOState transitions, lifecycle events, periodic healthYes
WARNINGAnomalies that self-recover (stale heartbeat, slow tick)Yes
ERRORFailures requiring attention (broadcast failed, API error)Yes

Required Fields

Beyond system and subsystem, include relevant entity IDs:

  • draft_id — for anything draft-related
  • user_id / username — for user-scoped actions
  • event_id — for event system logs
  • duration_s / elapsed_ms — for timing-sensitive operations
  • reason — for skipped/stopped/failed actions
  • error — for exception context (str(e), never the full traceback)

References

Grafana Queries

# All herodraft heartbeat logs
{service_name="backend"} | json | system="herodraft" | subsystem="heartbeat"

# Slow ticks
{service_name="backend"} | json | event="tick_slow"

# All errors across systems
{service_name="backend"} | json | level="error"

# Filter by draft
{service_name="backend"} | json | draft_id="42"

Run these from the CLI with gcx (context draftforge → kettle.grafana.net). Pass --agent=false or Claude Code's auto agent-mode suppresses the output:

gcx logs query '{service_name="backend"} | json | level="error"' --since 24h -o raw --agent=false

The discord service mixes structlog JSON with plain-text discord.py lines, so | json drops half of them — use line filters (|= "ERROR") there. Full examples (error breakdown, silence detection, request/trace correlation): references/grafana-loki.md.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

aesthetic

무료

Create aesthetically beautiful interfaces following proven design principles. Use when building UI/UX, analyzing designs from inspiration sites, generating design images with ai-multimodal, implementing visual hierarchy and color theory, adding micro-interactions, or creating design documentation. Includes workflows for capturing and analyzing inspiration screenshots with chrome-devtools and ai-multimodal, iterative design image generation until aesthetic standards are met, and comprehensive design system guidance covering BEAUTIFUL (aesthetic principles), RIGHT (functionality/accessibility), SATISFYING (micro-interactions), and PEAK (storytelling) stages. Integrates with chrome-devtools, ai-multimodal, media-processing, ui-styling, and web-frameworks skills.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

kettleofketchup/DraftForge152026년 10월 19일 업데이트

Proper usage of Bash and file operation tools. Use this skill when executing shell commands, writing files, or when tempted to use echo/cat/heredoc to pipe content to files. Prevents permission circumvention patterns like piping multiline content through echo instead of using Write tool. Covers Bash tool, Write tool, Edit tool, and Read tool best practices.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

kettleofketchup/DraftForge152026년 10월 19일 업데이트

brand

무료

DraftForge brand/theming review. Flags raw <button> over PrimaryButton/SecondaryButton, hardcoded violet/slate over brand tokens, inline styles, missing UserAvatar/EntityBreadcrumb.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

kettleofketchup/DraftForge152026년 10월 19일 업데이트

Browser automation, debugging, and performance analysis using Puppeteer CLI scripts. Use for automating browsers, taking screenshots, analyzing performance, monitoring network traffic, web scraping, form automation, and JavaScript debugging.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

kettleofketchup/DraftForge152026년 10월 19일 업데이트

Django Redis caching with django-cacheops. This skill should be used when implementing caching, adding cache invalidation, optimizing API performance, modifying models that affect cached data, or debugging cache-related issues in the Django backend.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

kettleofketchup/DraftForge152026년 10월 19일 업데이트

Frontend development guidelines for React/TypeScript applications. Modern patterns including Suspense, lazy loading, useSuspenseQuery, file organization with features directory, MUI v7 styling, TanStack Router, performance optimization, and TypeScript best practices. Use when creating components, pages, features, fetching data, styling, routing, or working with frontend code.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

kettleofketchup/DraftForge152026년 10월 19일 업데이트

kettleofketchup의 스킬 모두 보기

이 스킬의 문제 신고