diff --git a/README.md b/README.md index 3399b7d..8d5b7d9 100644 --- a/README.md +++ b/README.md @@ -222,7 +222,7 @@ If you need Dolphie running incognito while always recording data to capture tho To activate Daemon mode, specify the `--daemon` option, which will automatically enable `--record`. This will transform Dolphie into a resource-efficient, passive, always-on monitoring process that continuously records data. It removes Textual's TUI and creates a log file for messages while also printing them to the console. -To run Dolphie in the background using daemon mode, I recommend `systemctl` for its flexibility and management capabilities (see the [service configuration example](https://github.com/charles-001/dolphie/blob/main/dolphie.service)). While alternatives like `nohup` or `tmux` can be used, they are not advisable due to their limited management features. +To run Dolphie in the background using daemon mode, I recommend `systemctl` for its flexibility and management capabilities (see the [service configuration example](https://github.com/charles-001/dolphie/blob/main/examples/dolphie.service)). While alternatives like `nohup` or `tmux` can be used, they are not advisable due to their limited management features. Additionally, check out the [config example](https://github.com/charles-001/dolphie/blob/main/examples/dolphie-daemon.cnf) as a helpful starting point for setting up this mode. In Daemon mode, metrics are retained for the last 10 minutes to support graphing, with performance schema metric deltas automatically reset at 10-minute intervals. This approach keeps data fresh and relevant, providing an accurate view of recent activity. diff --git a/dolphie/Modules/CommandManager.py b/dolphie/Modules/CommandManager.py index 83312d5..d00bf10 100644 --- a/dolphie/Modules/CommandManager.py +++ b/dolphie/Modules/CommandManager.py @@ -35,6 +35,12 @@ def __init__(self): "description": "Toggle display of threads that only have an active transaction", }, "p": {"human_key": "p", "description": "Toggle pause for refreshing of panels"}, + "P": { + "human_key": "P", + "description": ( + "Toggle between Information Schema and Performance Schema for the Processlist panel" + ), + }, "s": {"human_key": "s", "description": "Toggle sorting for Age in Processlist panel"}, "placeholder_3": {"human_key": "", "description": ""}, "l": {"human_key": "l", "description": "Display the most recent deadlock"}, @@ -62,10 +68,6 @@ def __init__(self): "E": {"human_key": "E", "description": "Export the processlist to a CSV file"}, "k": {"human_key": "k", "description": "Kill thread by its ID"}, "K": {"human_key": "K", "description": "Kill threads by parameter(s)"}, - "P": { - "human_key": "P", - "description": "Switch between using Info/Perf Schema for Processlist panel", - }, "q": {"human_key": "q", "description": "Quit"}, "r": {"human_key": "r", "description": "Set the refresh interval"}, "R": {"human_key": "R", "description": "Reset all metrics"}, diff --git a/dolphie/Modules/TabManager.py b/dolphie/Modules/TabManager.py index f130aac..4fceef9 100644 --- a/dolphie/Modules/TabManager.py +++ b/dolphie/Modules/TabManager.py @@ -219,7 +219,7 @@ def toggle_metric_graph_tabs_display(self): self.dashboard_replay_container.display = False # Loop the metrics and update the graph switch values based on the tab's metric data so each tab can have - # its own set of visible graphs + # its own set of visible metrics for metric_instance_name, metric_instance in self.dolphie.metric_manager.metrics.__dict__.items(): for metric, metric_data in metric_instance.__dict__.items(): if ( diff --git a/dolphie/app.py b/dolphie/app.py index adc178d..4bf7107 100755 --- a/dolphie/app.py +++ b/dolphie/app.py @@ -90,8 +90,8 @@ def __init__(self, *args, **kwargs): self.dolphie_app: DolphieApp = self.app def async_command(self, key: str): - """Helper function to call the capture_key command asynchronously.""" - self.app.call_later(self.dolphie_app.capture_key, key) + """Helper function to call the process_key_event command asynchronously.""" + self.app.call_later(self.dolphie_app.process_key_event, key) def get_command_hits(self): """Helper function to get all commands and format them for discovery or search.""" @@ -1130,9 +1130,9 @@ async def on_key(self, event: events.Key): if len(self.screen_stack) > 1: return - await self.capture_key(event.key) + await self.process_key_event(event.key) - async def capture_key(self, key): + async def process_key_event(self, key): tab = self.tab_manager.active_tab if not tab: return @@ -1511,15 +1511,16 @@ def command_get_input(data): if key == "P": if dolphie.use_performance_schema_for_processlist: dolphie.use_performance_schema_for_processlist = False - self.notify("Switched to using [b highlight]Information Schema[/b highlight] for processlist") + self.notify("Switched to using [b highlight]Information Schema[/b highlight] for Processlist panel") else: if dolphie.performance_schema_enabled: dolphie.use_performance_schema_for_processlist = True - self.notify("Switched to using [b highlight]Performance Schema[/b highlight] for processlist") + self.notify("Switched to using [b highlight]Performance Schema[/b highlight] for Processlist panel") else: self.notify( "You can't switch to [b highlight]Performance Schema[/b highlight] for " - "processlist because it isn't enabled" + "Processlist panel because it isn't enabled", + severity="warning", ) elif key == "q": diff --git a/examples/dolphie-daemon.cnf b/examples/dolphie-daemon.cnf new file mode 100644 index 0000000..13ed65b --- /dev/null +++ b/examples/dolphie-daemon.cnf @@ -0,0 +1,11 @@ +[dolphie] +user = dolphie +password = super_secret_password +socket = /var/run/mysqld/mysqld.sock + +refresh_interval = 2 +replay_retention_hours = 48 + +daemon_mode = true +daemon_mode_log_file = /var/log/dolphie/daemon.log +replay_dir = /var/lib/dolphie/replays diff --git a/examples/dolphie.service b/examples/dolphie.service new file mode 100644 index 0000000..01a216a --- /dev/null +++ b/examples/dolphie.service @@ -0,0 +1,14 @@ +[Unit] +Description=Dolphie Daemon Service +After=mysql.service + +[Service] +User=dolphie +ExecStart=/usr/local/bin/dolphie --config-file /etc/dolphie/dolphie-daemon.cnf +StandardOutput=journal +StandardError=journal +Environment=PYTHONUNBUFFERED=1 +Restart=on-failure + +[Install] +WantedBy=multi-user.target diff --git a/poetry.lock b/poetry.lock index 8ed1d65..1d2443a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -660,13 +660,13 @@ doc = ["sphinx"] [[package]] name = "textual" -version = "0.88.0" +version = "0.88.1" description = "Modern Text User Interface framework" optional = false python-versions = "<4.0.0,>=3.8.1" files = [ - {file = "textual-0.88.0-py3-none-any.whl", hash = "sha256:87a1085a403e3a95aa4b954c530d46947d830e9ad4b8c15490104c0b4a452b6a"}, - {file = "textual-0.88.0.tar.gz", hash = "sha256:bf9cc3ec9d34957c361eabf739e59272295323478cc822633fb0a7b7cc2a0ac3"}, + {file = "textual-0.88.1-py3-none-any.whl", hash = "sha256:f2db8ce892007f724dab57a2b791e55f9d7ce04d333c50fb4b6fb7f3990d4cec"}, + {file = "textual-0.88.1.tar.gz", hash = "sha256:9c56d953dc7d1a8ddf06acc910d9224027e02416551f92920e70f435bd28e062"}, ] [package.dependencies] @@ -1010,4 +1010,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "274b7099ec3c84e251a1113088aa1fd355ababa2d656570394f104ec85c9c1ab" +content-hash = "1387a354e4f0a6c86c76bea65a23e115971ddc39f507e8498e7fffa29e918d9b" diff --git a/pyproject.toml b/pyproject.toml index 3f78ad8..ace72c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ myloginpath = "^0.0.4" packaging = "^24.2" requests = "^2.32.3" sqlparse = "^0.5.2" -textual = {extras = ["syntax"], version = "^0.88.0"} +textual = {extras = ["syntax"], version = "^0.88.1"} charset-normalizer = "^3.4.0" plotext = "^5.3.2" zstandard = "^0.23.0"