Daily Tips - Real-time Logs on Dash 📑

Hi there,

@Emil published a very cool and new release of dash-extensions yesterday. It brings a lot of useful special components. Today I’m going to try EventSource, which is a component for listening to Server-Sent Events (SSE).

I’m going to use it to display logs on a web page. This is the result.

sse

First, we should have a log file, let me use logging to simulate a log output.

import logging
import time

logging.basicConfig(
    level=logging.DEBUG,
    filename="/tmp/test.log",
    format="%(levelname)-8s : %(message)s",
)

s = 1
while True:
    logging.warning(f"I'm warning {s}.")
    time.sleep(3)
    s += 1

Then read the log and stream it out.

import asyncio
import uvicorn
import tailer
from sse_starlette import EventSourceResponse
from starlette.applications import Starlette
from starlette.middleware import Middleware
from starlette.middleware.cors import CORSMiddleware

middleware = Middleware(CORSMiddleware, allow_origins=["*"], allow_headers=["*"])
server = Starlette(middleware=[middleware])


async def logCheck(request):
    for line in tailer.follow(open("/tmp/test.log")):
        if await request.is_disconnected():
            print("Disconnected.")
            break
        await asyncio.sleep(1)
        yield line


@server.route("/log")
async def sse(request):
    generator = logCheck(request)
    return EventSourceResponse(generator)


if __name__ == "__main__":
    uvicorn.run(server, port=5000)

Next, the Dash application.

from dash_extensions import EventSource, Purify
from dash_extensions.enrich import (
    html,
    Output,
    Input,
    State,
    DashProxy,
    ClientsideFunction,
)


# Create small example app.
app = DashProxy(__name__)

app.layout = html.Div(
    [
        EventSource(id="sse", url="http://127.0.0.1:5000/log"),
        Purify(id="log-output", className="log-box"),
    ]
)

app.clientside_callback(
    ClientsideFunction(namespace="clientside", function_name="update_log"),
    Output("log-output", "html"),
    Input("sse", "message"),
    State("log-output", "html"),
)

if __name__ == "__main__":
    app.run_server(debug=True)
window.dash_clientside = Object.assign({}, window.dash_clientside, {
    clientside: {
        update_log: (msg, html) => {
            if (!msg) { return };
            if (!html) {
                return '<pre>' +
                    msg.replace('WARNING', "<span class='log-color--purple'>WARNING</span>") + '</pre>';
            } else {
                return html + '<pre>' +
                    msg.replace('WARNING', "<span class='log-color--purple'>WARNING</span>") + '</pre>';
            };
        }

    }
});

It looks like I might have to find a component dedicated to displaying logs to have a good outcome. :thinking:
Does anyone have a good recommendation?






Hope you like this. XD

Keywords: SSE, Server-Sent Event, dash-extensions, EventSource, logging, WebSocket

Other Daily Tips series:
Daily Tips - If I have a Bunch of Triggers
Daily Tips - Share the Function
Daily Tips - How many Ways to share Dash in a company?
Daily Tips - Give your Component a Name
Daily Tips - Share Dash to Social Media
Daily Tips - Double-click to open Dash
Daily Tips - What rows of data have I modified?
Daily Tips - Write the Simplest Client-side Callback
Daily Tips - Some simple Expressions
Daily Tips - IoT? Real Real-time Data and Live Update
Daily Tips - Which formatter is your favorite?
Daily Tips - Convert a React Component to Dash

6 Likes