Created
February 14, 2026 04:22
-
-
Save minrk/744159e07fc6a1f5512d1b92728537e6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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