Skip to content

Instantly share code, notes, and snippets.

@minrk
Created February 14, 2026 04:22
Show Gist options
  • Select an option

  • Save minrk/744159e07fc6a1f5512d1b92728537e6 to your computer and use it in GitHub Desktop.

Select an option

Save minrk/744159e07fc6a1f5512d1b92728537e6 to your computer and use it in GitHub Desktop.
<html>
<head>
<title>test</title>
</head>
<body>
<div id="out"></div>
<script type="text/javascript">
function onMessage(evt) {
const msg = JSON.parse(evt.data);
console.log(msg);
const out = document.getElementById("out");
const dest = document.createElement("pre");
dest.innerText = msg.msg;
out.appendChild(dest);
};
const ws = new WebSocket("/ws")
ws.onmessage = onMessage;
</script>
</body>
</html>
from contextvars import ContextVar
import logging
from tornado import web
import asyncio
import tornado
from tornado.websocket import WebSocketHandler, WebSocketClosedError
from tornado.options import define, options, parse_command_line
from tornado.log import app_log
logger = logging.getLogger("test")
class ContextWebSocketHandler(logging.Handler):
def emit(self, record):
handler = self.ws_handler.get()
formatted = self.format(record)
if handler:
msg = {
"msg": formatted,
"args": record.args,
"extra": record.__dict__,
}
try:
print("sending", msg)
handler.write_message(msg)
except WebSocketClosedError:
app_log.warning("Got message without on closed handler: %s", formatted)
else:
# not handled
app_log.warning("Got message without handler: %s", formatted)
ContextWebSocketHandler.ws_handler = ContextVar("ws_handler", default=None)
class MainHandler(web.RequestHandler):
def get(self):
with open("index.html") as f:
self.write(f.read())
counter = 0
class WSLogHandler(WebSocketHandler):
async def produce_logs(self):
for i in range(10):
logger.info("msg %i %i", self._id, i)
await asyncio.sleep(1)
logger.info("done %i", self._id)
self.close()
async def open(self):
global counter
self._id = counter
counter += 1
ContextWebSocketHandler.ws_handler.set(self)
asyncio.create_task(self.produce_logs())
def on_close(self):
print("closing!", self._id)
async def main():
define("port", default=9999, help="run on the given port", type=int)
logger.propogate = False
logger.addHandler(ContextWebSocketHandler())
logger.setLevel(logging.INFO)
parse_command_line()
app_log.info(f"Listening on 127.0.0.1:{options.port}")
application = tornado.web.Application([(r"/", MainHandler), ("/ws", WSLogHandler)])
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(options.port, "127.0.0.1")
await asyncio.Event().wait()
if __name__ == "__main__":
asyncio.run(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment