# sockets.py
from channels.generic.websocket import AsyncWebsocketConsumer
class BaseSocketConsumer(AsyncWebsocketConsumer):
...
async def connect(self):
await self.accept()
await self.send(text_data="accepted")
self.initialize()
...
django-channels에서 내부 메소드의 로그를 찍을 때 어떻게 django channels의 이름을 출력할까?
channel_name 인자로 전달 → method, layer depth가 늘어날 때 마다 channel_name을 인자로 전달해야함(좋지 않은 패턴)
contextvars(threading.local() 비동기 버전)를 이용해 전달 → good
from contextvars import ContextVar, copy_context
channel_context = ContextVar("channel_context", default="not_yet")
def get_context_var(var_name: str) -> str | None:
var = copy_context()
for context, value in var.items():
if var_name == context.name:
return value
return None
def set_context_var(value: str) -> None:
channel_context.set(value)
# sockets
class AppSocketConsumer(AsyncWebsocketConsumer):
async def connect(self):
await self.accept()
self.initialize()
...
def initialize():
...
set_context_var(self.channel_name[-10:])
await self.start_worker()
def start_workers(self):
for worker_id in range(self.config.max_concurrent_requests):
worker_task = asyncio.create_task(
coro=self.worker(), # worker 작업 내에서 channel_name이 찍히길 원함
name=f"request_worker_{worker_id}"
)
self.workers.append(worker_task)
ContextVars는 하위 비동기 작업에 복사됨(전파)