Using Watchdog to monitor a directory in Dash

161 views Asked by At

I'm trying to include a log monitor in Dash, using Watchdog. I've got a simple dashboard:

from dash import Dash, html, dcc, callback, Output, Input
from jupyter_dash import JupyterDash

log_display = dcc.Textarea(
    id='log_display', 
    placeholder='(log data will show up here)', 
    value="",
    disabled=True, 
    style={'width': '100%', 'height': 400, "margin-top": "15px", "margin-bottom": "15px"}
)

app = JupyterDash(__name__)
app.layout = html.Div([
    html.H3("CONSOLE"),
    log_display
])

And I've got a simple Watchdog implementation that puts a notification in the TextArea (taken almost verbatim from the Watchdog quickstart example):

from watchdog.observers import Observer
from watchdog.events import LoggingEventHandler, FileSystemEventHandler

class LogEventHandler(FileSystemEventHandler):
    @staticmethod
    def on_any_event(event):
        log_display.value = "An event occurred"
        print("An event occurred")


class LogDirectoryWatcher:
    watchDirectory = os.path.expanduser("~")
 
    def __init__(self):
        self.observer = Observer()
 
    def run(self):
        event_handler = LogEventHandler()
        self.observer.schedule(event_handler, self.watchDirectory, recursive = True)
        self.observer.start()
        try:
            while True:
                time.sleep(5)
        except:
            self.observer.stop()
            print("Observer Stopped")
        self.observer.join()

The observer seems to work perfectly and the console message shows up, but the notification text doesn't show up the TextArea.

From what I understand, Dash components need to be updated in callbacks generated in the UI. I'm not sure how to connect these two things.

1

There are 1 answers

3
EricLavault On

You can use a dcc.Interval component for monitoring and updating the log display component every few (milli)seconds.

dcc.Interval is a component that will fire a callback periodically. Use it to update your app in realtime without needing to refresh the page or click on any buttons.

For example :

app.layout = html.Div([
    html.H3("CONSOLE"),
    dcc.Interval(
        id='log_interval',
        interval=1000, # milliseconds
        n_intervals=0  # number of times the interval has passed
    ),
    log_display
])

@callback(Output('log_display', 'value'),
          Input('log_interval', 'n_intervals'))
def update_log(n):
    return log_display.value

See also Basic Dash Callbacks