title: Background thread logging to a Server Sent Event stream in a Flask app
body: <p>I'm trying to build a Flask application that has some task running in the background. This task (a worker) uses standard <code>logging</code> module for logging what is going on. I would like to use Server Sent Events to push the log messages directly to the web browser, but I can't get them broadcasted by <code>gevent</code>.</p>
  
  <p>In the following snippet the worker is launched properly, <code>SSEHandler.emit</code> method is called as it should, but the <code>notify</code> function doesn't seem to be executed after I do <code>gevent.spawn</code>.</p>
  
  <h2>main.py</h2>
  
  <pre><code>import gevent
  from gevent.wsgi import WSGIServer
  from gevent.queue import Queue
  
  from flask import Flask, Response
  
  import time
  import logging
  import threading
  from worker import Worker
  
  class SSEHandler(logging.Handler):
  
      def __init__(self):
          logging.Handler.__init__(self)        
          self.subscriptions = []
  
      def emit(self, record):
          try:
              msg = self.format(record)
              print "sending", msg
              def notify(subs, msg):
                  print "broadcasting!"
                  for sub in subs[:]:
                      sub.put(msg)
  
              gevent.spawn(notify, self.subscriptions, msg)
  
          except (KeyboardInterrupt, SystemExit):
              raise
          except:
              self.handleError(record)
  
      def subscribe(self):
          print "subscribed"
          q = Queue()
          self.subscriptions.append(q)
          try:
              while True:
                  result = q.get()
                  yield "data: %s\n\n"%result
          except GeneratorExit: # Or maybe use flask signals
              subscriptions.remove(q)
  
  
  
  app = Flask(__name__)
  handler = SSEHandler()
  handler.setLevel(logging.DEBUG)
  worker = None
  
  # Client code consumes like this.
  @app.route("/")
  def index():
      debug_template = """
       &lt;html&gt;
         &lt;head&gt;
         &lt;/head&gt;
         &lt;body&gt;
           &lt;h1&gt;Server sent events&lt;/h1&gt;
           &lt;div id="event"&gt;&lt;/div&gt;
           &lt;script type="text/javascript"&gt;
  
           var eventOutputContainer = document.getElementById("event");
           var evtSrc = new EventSource("/subscribe");
  
           evtSrc.onmessage = function(e) {
               console.log(e.data);
               eventOutputContainer.innerHTML = e.data;
           };
  
           &lt;/script&gt;
         &lt;/body&gt;
       &lt;/html&gt;
      """
      return(debug_template)
  
  
  @app.route("/subscribe")
  def subscribe():
      return Response(handler.subscribe(), mimetype="text/event-stream")
  
  @app.route("/start")
  def start():
      def run():
          global worker
          global handler
          worker = Worker(handler)
          worker.go()
  
      threading.Thread(target=run).start()
      return "Going"
  
  if __name__ == "__main__":
      app.debug = True
      server = WSGIServer(("", 5000), app)
      server.serve_forever()
  </code></pre>
  
  <h2>worker.py</h2>
  
  <pre><code>import logging
  import time
  
  class Worker:
      def __init__(self, handler):
          self.log = logging.getLogger('sselog.worker.Worker')
          self.log.setLevel(logging.DEBUG)
          self.log.addHandler(handler)
  
          self.log.info("Initialized")
  
      def go(self):
          i = 0
          while True:
              time.sleep(1)
              self.log.info("I'm working so hard %u", i)
              i+=1
  </code></pre>