Implement a console in Dash which gets updated with status of intermediate steps on the server

Viewed 764

What I have : Basically I have a dashboard in Python's Dash which has a button called GetData. The callback handler for this button gets data from 3 sources, draws 3 charts and sends back an output Div wrapping all of these charts nicely. I also have a text area on the client's screen which updates after all work is done on the server, serving as a console.

What I want:

A dedicated area on the client's screen to keep a running log of actions initiated on the server by the client. This would mean that,

a) I would like to update the text in the console by appending status of intermediate steps on the server. Way I see it, I can only update the value in the text area ONCE, right at the end of the button callback handler. b) I would also like to bind this console as output to multiple button callbacks so that I can send a log of what's happening on the server with the client's request back to the client.

Thoughts?

3 Answers

I was able to achieve this by,

a) Writing to a logfile
b) Using a dcc.Interval component with output bound to a text area that polls the logfile and shows the last 20 rows from it

So far there is only one user/client but once there are more will need to think about filtering and the like.

For this kind of use case, i typically use variations of following approach

  1. Generate a unique key for each log instance, e.g. if you want all logs for the current user, you could use the session id or a GUID generated on page load
  2. During callback executing on server, logging output is written to a server side resource (a redis cache, a file etc.) identified by the key
  3. Using a callback triggered by Interval component and with the key as State (so that the correct log can be identified), the log is read from the server

I'm not sure if this will do the job, but you could construct a logging decorator right before the callback as such:

@callback(...)
@myLogger
def function(a, b, c):
    pass

def myLogger(fn):
     @wraps    
     def wrapper(*args, **kwargs)
        code_info = fn.__code__
        code_vars = fn.__code__.co_names ## There are many options here
                                         ## check fn.__code__.__dict__ 
                                         ## in repl
        retval = fn(args, kwargs)
        print(f"func: {fn.__name__}, args: {args}, kwargs: {kwargs}, retval: {retval}")
        return retval
     return wrapper

The above is more or less psudo-code for a function decorator that can extract information from function calls decorated with it. It queries the code object from the function, evaluates the function, prints a collection of information to the terminal and returns the output just as it would normally. Notice that myLogger comes after the callback, as we expect to compose the functions as follows

callback(myLogger(function(...)))
Related