added grpc error display and updated grpc calls to catch and display grpc exceptions

This commit is contained in:
Blake Harnden 2019-12-09 22:50:26 -08:00
parent 33e3a46146
commit d78ef86cef
11 changed files with 329 additions and 228 deletions

View file

@ -6,7 +6,6 @@ import logging
import os
import time
from pathlib import Path
from tkinter import messagebox
import grpc
@ -14,6 +13,7 @@ from core.api.grpc import client, core_pb2
from coretk import appconfig
from coretk.dialogs.mobilityplayer import MobilityPlayer
from coretk.dialogs.sessions import SessionsDialog
from coretk.errors import show_grpc_error
from coretk.graph import tags
from coretk.graph.shape import AnnotationData, Shape
from coretk.graph.shapeutils import ShapeType
@ -206,85 +206,92 @@ class CoreClient:
self.reset()
# get session data
response = self.client.get_session(self.session_id)
session = response.session
self.state = session.state
self.client.events(self.session_id, self.handle_events)
self.client.throughputs(self.handle_throughputs)
try:
response = self.client.get_session(self.session_id)
session = response.session
self.state = session.state
self.client.events(self.session_id, self.handle_events)
self.client.throughputs(self.handle_throughputs)
# get location
if query_location:
response = self.client.get_session_location(self.session_id)
self.location = response.location
# get location
if query_location:
response = self.client.get_session_location(self.session_id)
self.location = response.location
# get emane models
response = self.client.get_emane_models(self.session_id)
self.emane_models = response.models
# get emane models
response = self.client.get_emane_models(self.session_id)
self.emane_models = response.models
# get hooks
response = self.client.get_hooks(self.session_id)
for hook in response.hooks:
self.hooks[hook.file] = hook
# get hooks
response = self.client.get_hooks(self.session_id)
for hook in response.hooks:
self.hooks[hook.file] = hook
# get mobility configs
response = self.client.get_mobility_configs(self.session_id)
for node_id in response.configs:
node_config = response.configs[node_id].config
self.mobility_configs[node_id] = node_config
# get mobility configs
response = self.client.get_mobility_configs(self.session_id)
for node_id in response.configs:
node_config = response.configs[node_id].config
self.mobility_configs[node_id] = node_config
# get emane config
response = self.client.get_emane_config(self.session_id)
self.emane_config = response.config
# get emane config
response = self.client.get_emane_config(self.session_id)
self.emane_config = response.config
# get emane model config
response = self.client.get_emane_model_configs(self.session_id)
for _id in response.configs:
config = response.configs[_id]
interface = None
node_id = _id
if _id >= 1000:
interface = _id % 1000
node_id = int(_id / 1000)
self.set_emane_model_config(node_id, config.model, config.config, interface)
# get emane model config
response = self.client.get_emane_model_configs(self.session_id)
for _id in response.configs:
config = response.configs[_id]
interface = None
node_id = _id
if _id >= 1000:
interface = _id % 1000
node_id = int(_id / 1000)
self.set_emane_model_config(
node_id, config.model, config.config, interface
)
# save and retrieve data, needed for session nodes
for node in session.nodes:
# get node service config and file config
self.created_nodes.add(node.id)
# save and retrieve data, needed for session nodes
for node in session.nodes:
# get node service config and file config
self.created_nodes.add(node.id)
# get wlan configs for wlan nodes
if node.type == core_pb2.NodeType.WIRELESS_LAN:
response = self.client.get_wlan_config(self.session_id, node.id)
self.wlan_configs[node.id] = response.config
# retrieve service configurations data for default nodes
elif node.type == core_pb2.NodeType.DEFAULT:
for service in node.services:
response = self.client.get_node_service(
self.session_id, node.id, service
)
if node.id not in self.service_configs:
self.service_configs[node.id] = {}
self.service_configs[node.id][service] = response.service
for file in response.service.configs:
response = self.client.get_node_service_file(
self.session_id, node.id, service, file
# get wlan configs for wlan nodes
if node.type == core_pb2.NodeType.WIRELESS_LAN:
response = self.client.get_wlan_config(self.session_id, node.id)
self.wlan_configs[node.id] = response.config
# retrieve service configurations data for default nodes
elif node.type == core_pb2.NodeType.DEFAULT:
for service in node.services:
response = self.client.get_node_service(
self.session_id, node.id, service
)
if node.id not in self.file_configs:
self.file_configs[node.id] = {}
if service not in self.file_configs[node.id]:
self.file_configs[node.id][service] = {}
self.file_configs[node.id][service][file] = response.data
if node.id not in self.service_configs:
self.service_configs[node.id] = {}
self.service_configs[node.id][service] = response.service
for file in response.service.configs:
response = self.client.get_node_service_file(
self.session_id, node.id, service, file
)
if node.id not in self.file_configs:
self.file_configs[node.id] = {}
if service not in self.file_configs[node.id]:
self.file_configs[node.id][service] = {}
self.file_configs[node.id][service][file] = response.data
# store links as created links
for link in session.links:
self.created_links.add(tuple(sorted([link.node_one_id, link.node_two_id])))
# store links as created links
for link in session.links:
self.created_links.add(
tuple(sorted([link.node_one_id, link.node_two_id]))
)
# draw session
self.app.canvas.reset_and_redraw(session)
# draw session
self.app.canvas.reset_and_redraw(session)
# get metadata
response = self.client.get_session_metadata(self.session_id)
self.parse_metadata(response.config)
# get metadata
response = self.client.get_session_metadata(self.session_id)
self.parse_metadata(response.config)
except grpc.RpcError as e:
show_grpc_error(e)
# update ui to represent current state
if self.is_runtime():
@ -363,25 +370,31 @@ class CoreClient:
:return: nothing
"""
response = self.client.create_session()
logging.info("created session: %s", response)
location_config = self.app.guiconfig["location"]
self.location = core_pb2.SessionLocation(
x=location_config["x"],
y=location_config["y"],
z=location_config["z"],
lat=location_config["lat"],
lon=location_config["lon"],
alt=location_config["alt"],
scale=location_config["scale"],
)
self.join_session(response.session_id, query_location=False)
try:
response = self.client.create_session()
logging.info("created session: %s", response)
location_config = self.app.guiconfig["location"]
self.location = core_pb2.SessionLocation(
x=location_config["x"],
y=location_config["y"],
z=location_config["z"],
lat=location_config["lat"],
lon=location_config["lon"],
alt=location_config["alt"],
scale=location_config["scale"],
)
self.join_session(response.session_id, query_location=False)
except grpc.RpcError as e:
show_grpc_error(e)
def delete_session(self, session_id=None):
if session_id is None:
session_id = self.session_id
response = self.client.delete_session(session_id)
logging.info("Deleted session result: %s", response)
try:
response = self.client.delete_session(session_id)
logging.info("deleted session result: %s", response)
except grpc.RpcError as e:
show_grpc_error(e)
def set_up(self):
"""
@ -413,21 +426,15 @@ class CoreClient:
x.node_type: set(x.services) for x in response.defaults
}
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.UNAVAILABLE:
messagebox.showerror("Server Error", "CORE Daemon Unavailable")
else:
messagebox.showerror("GRPC Error", e.details())
show_grpc_error(e)
self.app.close()
def get_session_state(self):
response = self.client.get_session(self.session_id)
logging.info("get session: %s", response)
return response.session.state
def edit_node(self, node_id, x, y):
position = core_pb2.Position(x=x, y=y)
self.client.edit_node(self.session_id, node_id, position, source="gui")
try:
self.client.edit_node(self.session_id, node_id, position, source="gui")
except grpc.RpcError as e:
show_grpc_error(e)
def start_session(self):
nodes = [x.core_node for x in self.canvas_nodes.values()]
@ -446,39 +453,51 @@ class CoreClient:
emane_config = None
start = time.perf_counter()
response = self.client.start_session(
self.session_id,
nodes,
links,
self.location,
hooks,
emane_config,
emane_model_configs,
wlan_configs,
mobility_configs,
service_configs,
file_configs,
)
self.set_metadata()
process_time = time.perf_counter() - start
logging.debug("start session(%s), result: %s", self.session_id, response.result)
self.app.statusbar.start_session_callback(process_time)
try:
response = self.client.start_session(
self.session_id,
nodes,
links,
self.location,
hooks,
emane_config,
emane_model_configs,
wlan_configs,
mobility_configs,
service_configs,
file_configs,
)
self.set_metadata()
process_time = time.perf_counter() - start
logging.debug(
"start session(%s), result: %s", self.session_id, response.result
)
self.app.statusbar.start_session_callback(process_time)
# display mobility players
for node_id, config in self.mobility_configs.items():
canvas_node = self.canvas_nodes[node_id]
mobility_player = MobilityPlayer(self.app, self.app, canvas_node, config)
mobility_player.show()
self.mobility_players[node_id] = mobility_player
# display mobility players
for node_id, config in self.mobility_configs.items():
canvas_node = self.canvas_nodes[node_id]
mobility_player = MobilityPlayer(
self.app, self.app, canvas_node, config
)
mobility_player.show()
self.mobility_players[node_id] = mobility_player
except grpc.RpcError as e:
show_grpc_error(e)
def stop_session(self, session_id=None):
if not session_id:
session_id = self.session_id
start = time.perf_counter()
response = self.client.stop_session(session_id)
process_time = time.perf_counter() - start
self.app.statusbar.stop_session_callback(process_time)
logging.debug("stopped session(%s), result: %s", session_id, response.result)
try:
response = self.client.stop_session(session_id)
logging.debug(
"stopped session(%s), result: %s", session_id, response.result
)
process_time = time.perf_counter() - start
self.app.statusbar.stop_session_callback(process_time)
except grpc.RpcError as e:
show_grpc_error(e)
def set_metadata(self):
# create canvas data
@ -502,9 +521,12 @@ class CoreClient:
logging.info("set session metadata: %s", response)
def launch_terminal(self, node_id):
response = self.client.get_node_terminal(self.session_id, node_id)
logging.info("get terminal %s", response.terminal)
os.system(f"xterm -e {response.terminal} &")
try:
response = self.client.get_node_terminal(self.session_id, node_id)
logging.info("get terminal %s", response.terminal)
os.system(f"xterm -e {response.terminal} &")
except grpc.RpcError as e:
show_grpc_error(e)
def save_xml(self, file_path):
"""
@ -513,9 +535,11 @@ class CoreClient:
:param str file_path: file path that user pick
:return: nothing
"""
response = self.client.save_xml(self.session_id, file_path)
logging.info("saved xml(%s): %s", file_path, response)
self.client.events(self.session_id, self.handle_events)
try:
response = self.client.save_xml(self.session_id, file_path)
logging.info("saved xml(%s): %s", file_path, response)
except grpc.RpcError as e:
show_grpc_error(e)
def open_xml(self, file_path):
"""
@ -524,9 +548,12 @@ class CoreClient:
:param str file_path: file to open
:return: session id
"""
response = self.client.open_xml(file_path)
logging.debug("open xml: %s", response)
self.join_session(response.session_id)
try:
response = self.client.open_xml(file_path)
logging.debug("open xml: %s", response)
self.join_session(response.session_id)
except grpc.RpcError as e:
show_grpc_error(e)
def get_node_service(self, node_id, service_name):
response = self.client.get_node_service(self.session_id, node_id, service_name)
@ -563,7 +590,7 @@ class CoreClient:
"""
node_protos = [x.core_node for x in self.canvas_nodes.values()]
link_protos = list(self.links.values())
if self.get_session_state() != core_pb2.SessionState.DEFINITION:
if self.state != core_pb2.SessionState.DEFINITION:
self.client.set_session_state(
self.session_id, core_pb2.SessionState.DEFINITION
)
@ -596,7 +623,7 @@ class CoreClient:
:return: nothing
"""
logging.debug("Close grpc")
logging.debug("close grpc")
self.client.close()
def next_node_id(self):

View file

@ -6,7 +6,10 @@ import tkinter as tk
import webbrowser
from tkinter import ttk
import grpc
from coretk.dialogs.dialog import Dialog
from coretk.errors import show_grpc_error
from coretk.images import ImageEnum, Images
from coretk.widgets import ConfigFrame
@ -52,9 +55,13 @@ class EmaneModelDialog(Dialog):
self.model = f"emane_{model}"
self.interface = interface
self.config_frame = None
self.config = self.app.core.get_emane_model_config(
self.node.id, self.model, self.interface
)
try:
self.config = self.app.core.get_emane_model_config(
self.node.id, self.model, self.interface
)
except grpc.RpcError as e:
show_grpc_error(e)
self.destroy()
self.draw()
def draw(self):

View file

@ -3,7 +3,10 @@ mobility configuration
"""
from tkinter import ttk
import grpc
from coretk.dialogs.dialog import Dialog
from coretk.errors import show_grpc_error
from coretk.widgets import ConfigFrame
PAD = 5
@ -20,7 +23,11 @@ class MobilityConfigDialog(Dialog):
self.canvas_node = canvas_node
self.node = canvas_node.core_node
self.config_frame = None
self.config = self.app.core.get_mobility_config(self.node.id)
try:
self.config = self.app.core.get_mobility_config(self.node.id)
except grpc.RpcError as e:
show_grpc_error(e)
self.destroy()
self.draw()
def draw(self):

View file

@ -1,8 +1,11 @@
import tkinter as tk
from tkinter import ttk
import grpc
from core.api.grpc.core_pb2 import MobilityAction
from coretk.dialogs.dialog import Dialog
from coretk.errors import show_grpc_error
from coretk.images import ImageEnum, Images
PAD = 5
@ -123,20 +126,29 @@ class MobilityPlayerDialog(Dialog):
def click_play(self):
self.set_play()
session_id = self.app.core.session_id
self.app.core.client.mobility_action(
session_id, self.node.id, MobilityAction.START
)
try:
self.app.core.client.mobility_action(
session_id, self.node.id, MobilityAction.START
)
except grpc.RpcError as e:
show_grpc_error(e)
def click_pause(self):
self.set_pause()
session_id = self.app.core.session_id
self.app.core.client.mobility_action(
session_id, self.node.id, MobilityAction.PAUSE
)
try:
self.app.core.client.mobility_action(
session_id, self.node.id, MobilityAction.PAUSE
)
except grpc.RpcError as e:
show_grpc_error(e)
def click_stop(self):
self.set_stop()
session_id = self.app.core.session_id
self.app.core.client.mobility_action(
session_id, self.node.id, MobilityAction.STOP
)
try:
self.app.core.client.mobility_action(
session_id, self.node.id, MobilityAction.STOP
)
except grpc.RpcError as e:
show_grpc_error(e)

View file

@ -3,8 +3,11 @@ import logging
import tkinter as tk
from tkinter import ttk
import grpc
from core.api.grpc import core_pb2
from coretk.dialogs.dialog import Dialog
from coretk.errors import show_grpc_error
from coretk.images import ImageEnum, Images
from coretk.widgets import CodeText, ListboxScroll
@ -47,44 +50,48 @@ class ServiceConfiguration(Dialog):
self.draw()
def load(self):
# create nodes and links in definition state for getting and setting service file
self.app.core.create_nodes_and_links()
service_configs = self.app.core.service_configs
if (
self.node_id in service_configs
and self.service_name in service_configs[self.node_id]
):
service_config = self.app.core.service_configs[self.node_id][
self.service_name
]
else:
service_config = self.app.core.get_node_service(
self.node_id, self.service_name
)
self.dependencies = [x for x in service_config.dependencies]
self.executables = [x for x in service_config.executables]
self.metadata = service_config.meta
self.filenames = [x for x in service_config.configs]
self.startup_commands = [x for x in service_config.startup]
self.validation_commands = [x for x in service_config.validate]
self.shutdown_commands = [x for x in service_config.shutdown]
self.validation_mode = service_config.validation_mode
self.validation_time = service_config.validation_timer
self.original_service_files = {
x: self.app.core.get_node_service_file(self.node_id, self.service_name, x)
for x in self.filenames
}
self.temp_service_files = {
x: self.original_service_files[x] for x in self.original_service_files
}
file_configs = self.app.core.file_configs
if (
self.node_id in file_configs
and self.service_name in file_configs[self.node_id]
):
for file, data in file_configs[self.node_id][self.service_name].items():
self.temp_service_files[file] = data
try:
# create nodes and links in definition state for getting and setting service file
self.app.core.create_nodes_and_links()
service_configs = self.app.core.service_configs
if (
self.node_id in service_configs
and self.service_name in service_configs[self.node_id]
):
service_config = self.app.core.service_configs[self.node_id][
self.service_name
]
else:
service_config = self.app.core.get_node_service(
self.node_id, self.service_name
)
self.dependencies = [x for x in service_config.dependencies]
self.executables = [x for x in service_config.executables]
self.metadata = service_config.meta
self.filenames = [x for x in service_config.configs]
self.startup_commands = [x for x in service_config.startup]
self.validation_commands = [x for x in service_config.validate]
self.shutdown_commands = [x for x in service_config.shutdown]
self.validation_mode = service_config.validation_mode
self.validation_time = service_config.validation_timer
self.original_service_files = {
x: self.app.core.get_node_service_file(
self.node_id, self.service_name, x
)
for x in self.filenames
}
self.temp_service_files = {
x: self.original_service_files[x] for x in self.original_service_files
}
file_configs = self.app.core.file_configs
if (
self.node_id in file_configs
and self.service_name in file_configs[self.node_id]
):
for file, data in file_configs[self.node_id][self.service_name].items():
self.temp_service_files[file] = data
except grpc.RpcError as e:
show_grpc_error(e)
def draw(self):
# self.columnconfigure(1, weight=1)
@ -366,30 +373,33 @@ class ServiceConfiguration(Dialog):
startup_commands = self.startup_commands_listbox.get(0, "end")
shutdown_commands = self.shutdown_commands_listbox.get(0, "end")
validate_commands = self.validate_commands_listbox.get(0, "end")
config = self.core.set_node_service(
self.node_id,
self.service_name,
startup_commands,
validate_commands,
shutdown_commands,
)
if self.node_id not in service_configs:
service_configs[self.node_id] = {}
if self.service_name not in service_configs[self.node_id]:
self.app.core.service_configs[self.node_id][self.service_name] = config
for file in self.modified_files:
file_configs = self.app.core.file_configs
if self.node_id not in file_configs:
file_configs[self.node_id] = {}
if self.service_name not in file_configs[self.node_id]:
file_configs[self.node_id][self.service_name] = {}
file_configs[self.node_id][self.service_name][
file
] = self.temp_service_files[file]
self.app.core.set_node_service_file(
self.node_id, self.service_name, file, self.temp_service_files[file]
try:
config = self.core.set_node_service(
self.node_id,
self.service_name,
startup_commands,
validate_commands,
shutdown_commands,
)
if self.node_id not in service_configs:
service_configs[self.node_id] = {}
if self.service_name not in service_configs[self.node_id]:
self.app.core.service_configs[self.node_id][self.service_name] = config
for file in self.modified_files:
file_configs = self.app.core.file_configs
if self.node_id not in file_configs:
file_configs[self.node_id] = {}
if self.service_name not in file_configs[self.node_id]:
file_configs[self.node_id][self.service_name] = {}
file_configs[self.node_id][self.service_name][
file
] = self.temp_service_files[file]
self.app.core.set_node_service_file(
self.node_id, self.service_name, file, self.temp_service_files[file]
)
except grpc.RpcError as e:
show_grpc_error(e)
self.destroy()
def display_service_file_data(self, event):

View file

@ -1,7 +1,10 @@
import logging
from tkinter import ttk
import grpc
from coretk.dialogs.dialog import Dialog
from coretk.errors import show_grpc_error
from coretk.widgets import ConfigFrame
PAD_X = 2
@ -12,17 +15,23 @@ class SessionOptionsDialog(Dialog):
def __init__(self, master, app):
super().__init__(master, app, "Session Options", modal=True)
self.config_frame = None
self.config = self.get_config()
self.draw()
def get_config(self):
try:
session_id = self.app.core.session_id
response = self.app.core.client.get_session_options(session_id)
return response.config
except grpc.RpcError as e:
show_grpc_error(e)
self.destroy()
def draw(self):
self.top.columnconfigure(0, weight=1)
self.top.rowconfigure(0, weight=1)
session_id = self.app.core.session_id
response = self.app.core.client.get_session_options(session_id)
logging.info("session options: %s", response)
self.config_frame = ConfigFrame(self.top, self.app, config=response.config)
self.config_frame = ConfigFrame(self.top, self.app, config=self.config)
self.config_frame.draw_config()
self.config_frame.grid(sticky="nsew")
@ -37,7 +46,10 @@ class SessionOptionsDialog(Dialog):
def save(self):
config = self.config_frame.parse_config()
session_id = self.app.core.session_id
response = self.app.core.client.set_session_options(session_id, config)
logging.info("saved session config: %s", response)
try:
session_id = self.app.core.session_id
response = self.app.core.client.set_session_options(session_id, config)
logging.info("saved session config: %s", response)
except grpc.RpcError as e:
show_grpc_error(e)
self.destroy()

View file

@ -3,8 +3,11 @@ import threading
import tkinter as tk
from tkinter import ttk
import grpc
from core.api.grpc import core_pb2
from coretk.dialogs.dialog import Dialog
from coretk.errors import show_grpc_error
from coretk.images import ImageEnum, Images
@ -14,8 +17,18 @@ class SessionsDialog(Dialog):
self.selected = False
self.selected_id = None
self.tree = None
self.sessions = self.get_sessions()
self.draw()
def get_sessions(self):
try:
response = self.app.core.client.get_sessions()
logging.info("sessions: %s", response)
return response.sessions
except grpc.RpcError as e:
show_grpc_error(e)
self.destroy()
def draw(self):
self.top.columnconfigure(0, weight=1)
self.draw_description()
@ -48,9 +61,7 @@ class SessionsDialog(Dialog):
self.tree.column("nodes", stretch=tk.YES)
self.tree.heading("nodes", text="Node Count")
response = self.app.core.client.get_sessions()
logging.info("sessions: %s", response)
for index, session in enumerate(response.sessions):
for index, session in enumerate(self.sessions):
state_name = core_pb2.SessionState.Enum.Name(session.state)
self.tree.insert(
"",

View file

@ -4,7 +4,10 @@ wlan configuration
from tkinter import ttk
import grpc
from coretk.dialogs.dialog import Dialog
from coretk.errors import show_grpc_error
from coretk.widgets import ConfigFrame
PAD = 5
@ -18,7 +21,11 @@ class WlanConfigDialog(Dialog):
self.canvas_node = canvas_node
self.node = canvas_node.core_node
self.config_frame = None
self.config = self.app.core.get_wlan_config(self.node.id)
try:
self.config = self.app.core.get_wlan_config(self.node.id)
except grpc.RpcError as e:
show_grpc_error(e)
self.destroy()
self.draw()
def draw(self):

8
coretk/coretk/errors.py Normal file
View file

@ -0,0 +1,8 @@
from tkinter import messagebox
def show_grpc_error(e):
title = [x.capitalize() for x in e.code().name.lower().split("_")]
title = " ".join(title)
title = f"GRPC {title}"
messagebox.showerror(title, e.details())

View file

@ -2,11 +2,14 @@ import logging
import tkinter as tk
from tkinter import font
import grpc
from core.api.grpc.core_pb2 import NodeType
from coretk.dialogs.emaneconfig import EmaneConfigDialog
from coretk.dialogs.mobilityconfig import MobilityConfigDialog
from coretk.dialogs.nodeconfig import NodeConfigDialog
from coretk.dialogs.wlanconfig import WlanConfigDialog
from coretk.errors import show_grpc_error
from coretk.graph import tags
from coretk.graph.enums import GraphMode
from coretk.graph.tooltip import CanvasTooltip
@ -138,8 +141,11 @@ class CanvasNode:
if self.app.core.is_runtime() and self.app.core.observer:
self.tooltip.text.set("waiting...")
self.tooltip.on_enter(event)
output = self.app.core.run(self.core_node.id)
self.tooltip.text.set(output)
try:
output = self.app.core.run(self.core_node.id)
self.tooltip.text.set(output)
except grpc.RpcError as e:
show_grpc_error(e)
def on_leave(self, event):
self.tooltip.on_leave(event)

View file

@ -10,7 +10,6 @@ from tkinter import filedialog, messagebox
import grpc
from core.api.grpc import core_pb2
from coretk.appconfig import XML_PATH
from coretk.dialogs.about import AboutDialog
from coretk.dialogs.canvasbackground import CanvasBackgroundDialog
@ -52,12 +51,7 @@ class MenuAction:
"menuaction.py: clean_nodes_links_and_set_configuration() Exiting the program"
)
try:
state = self.app.core.get_session_state()
if (
state == core_pb2.SessionState.SHUTDOWN
or state == core_pb2.SessionState.DEFINITION
):
if not self.app.core.is_runtime():
self.app.core.delete_session()
if quitapp:
self.app.quit()
@ -73,7 +67,7 @@ class MenuAction:
elif quitapp:
self.app.quit()
except grpc.RpcError:
logging.error("error getting session state")
logging.exception("error deleting session")
if quitapp:
self.app.quit()