diff --git a/daemon/core/gui/data/icons/observe.gif b/daemon/core/gui/data/icons/observe.gif
deleted file mode 100644
index 6b66e730..00000000
Binary files a/daemon/core/gui/data/icons/observe.gif and /dev/null differ
diff --git a/daemon/core/gui/data/icons/observe.png b/daemon/core/gui/data/icons/observe.png
new file mode 100644
index 00000000..e32005da
Binary files /dev/null and b/daemon/core/gui/data/icons/observe.png differ
diff --git a/daemon/core/gui/dialogs/observers.py b/daemon/core/gui/dialogs/observers.py
index 6911e1b8..d1812b64 100644
--- a/daemon/core/gui/dialogs/observers.py
+++ b/daemon/core/gui/dialogs/observers.py
@@ -104,7 +104,8 @@ class ObserverDialog(Dialog):
             self.observers.insert(tk.END, name)
             self.name.set("")
             self.cmd.set("")
-            self.app.menubar.draw_custom_observers()
+            self.app.menubar.observers_menu.draw_custom()
+            self.app.toolbar.observers_menu.draw_custom()
         else:
             messagebox.showerror("Observer Error", f"{name} already exists")
 
@@ -132,7 +133,8 @@ class ObserverDialog(Dialog):
             self.observers.selection_clear(0, tk.END)
             self.save_button.config(state=tk.DISABLED)
             self.delete_button.config(state=tk.DISABLED)
-            self.app.menubar.draw_custom_observers()
+            self.app.menubar.observers_menu.draw_custom()
+            self.app.toolbar.observers_menu.draw_custom()
 
     def handle_observer_change(self, event: tk.Event):
         selection = self.observers.curselection()
diff --git a/daemon/core/gui/menubar.py b/daemon/core/gui/menubar.py
index 69db0092..62a9ceae 100644
--- a/daemon/core/gui/menubar.py
+++ b/daemon/core/gui/menubar.py
@@ -23,23 +23,13 @@ from core.gui.dialogs.sessionoptions import SessionOptionsDialog
 from core.gui.dialogs.sessions import SessionsDialog
 from core.gui.dialogs.throughput import ThroughputDialog
 from core.gui.nodeutils import ICON_SIZE
+from core.gui.observers import ObserversMenu
 from core.gui.task import ProgressTask
 
 if TYPE_CHECKING:
     from core.gui.app import Application
 
 MAX_FILES = 3
-OBSERVERS = {
-    "List Processes": "ps",
-    "Show Interfaces": "ip address",
-    "IPV4 Routes": "ip -4 route",
-    "IPV6 Routes": "ip -6 route",
-    "Listening Sockets": "ss -tuwnl",
-    "IPv4 MFC Entries": "ip -4 mroute show",
-    "IPv6 MFC Entries": "ip -6 mroute show",
-    "Firewall Rules": "iptables -L",
-    "IPSec Policies": "setkey -DP",
-}
 
 
 class Menubar(tk.Menu):
@@ -58,8 +48,6 @@ class Menubar(tk.Menu):
         self.recent_menu = None
         self.edit_menu = None
         self.observers_menu = None
-        self.observers_var = tk.StringVar(value=tk.NONE)
-        self.observers_custom_index = None
         self.draw()
 
     def draw(self) -> None:
@@ -201,42 +189,9 @@ class Menubar(tk.Menu):
         """
         Create observer widget menu item and create the sub menu items inside
         """
-        self.observers_menu = tk.Menu(widget_menu)
-        self.observers_menu.add_command(
-            label="Edit Observers", command=self.click_edit_observer_widgets
-        )
-        self.observers_menu.add_separator()
-        self.observers_menu.add_radiobutton(
-            label="None",
-            variable=self.observers_var,
-            value="none",
-            command=lambda: self.core.set_observer(None),
-        )
-        for name in sorted(OBSERVERS):
-            cmd = OBSERVERS[name]
-            self.observers_menu.add_radiobutton(
-                label=name,
-                variable=self.observers_var,
-                value=name,
-                command=partial(self.core.set_observer, cmd),
-            )
-        self.observers_custom_index = self.observers_menu.index(tk.END) + 1
-        self.draw_custom_observers()
+        self.observers_menu = ObserversMenu(widget_menu, self.app)
         widget_menu.add_cascade(label="Observer Widgets", menu=self.observers_menu)
 
-    def draw_custom_observers(self) -> None:
-        current_observers_index = self.observers_menu.index(tk.END) + 1
-        if self.observers_custom_index < current_observers_index:
-            self.observers_menu.delete(self.observers_custom_index, tk.END)
-        for name in sorted(self.core.custom_observers):
-            observer = self.core.custom_observers[name]
-            self.observers_menu.add_radiobutton(
-                label=name,
-                variable=self.observers_var,
-                value=name,
-                command=partial(self.core.set_observer, observer.cmd),
-            )
-
     def create_adjacency_menu(self, widget_menu: tk.Menu) -> None:
         """
         Create adjacency menu item and the sub menu items inside
diff --git a/daemon/core/gui/observers.py b/daemon/core/gui/observers.py
new file mode 100644
index 00000000..27d0a26e
--- /dev/null
+++ b/daemon/core/gui/observers.py
@@ -0,0 +1,66 @@
+import tkinter as tk
+from functools import partial
+from typing import TYPE_CHECKING
+
+from core.gui.dialogs.observers import ObserverDialog
+
+if TYPE_CHECKING:
+    from core.gui.app import Application
+
+OBSERVERS = {
+    "List Processes": "ps",
+    "Show Interfaces": "ip address",
+    "IPV4 Routes": "ip -4 route",
+    "IPV6 Routes": "ip -6 route",
+    "Listening Sockets": "ss -tuwnl",
+    "IPv4 MFC Entries": "ip -4 mroute show",
+    "IPv6 MFC Entries": "ip -6 mroute show",
+    "Firewall Rules": "iptables -L",
+    "IPSec Policies": "setkey -DP",
+}
+
+
+class ObserversMenu(tk.Menu):
+    def __init__(self, master: tk.BaseWidget, app: "Application") -> None:
+        super().__init__(master)
+        self.app = app
+        self.observer = tk.StringVar(value=tk.NONE)
+        self.custom_index = 0
+        self.draw()
+
+    def draw(self) -> None:
+        self.add_command(label="Edit Observers", command=self.click_edit)
+        self.add_separator()
+        self.add_radiobutton(
+            label="None",
+            variable=self.observer,
+            value="none",
+            command=lambda: self.app.core.set_observer(None),
+        )
+        for name in sorted(OBSERVERS):
+            cmd = OBSERVERS[name]
+            self.add_radiobutton(
+                label=name,
+                variable=self.observer,
+                value=name,
+                command=partial(self.app.core.set_observer, cmd),
+            )
+        self.custom_index = self.index(tk.END) + 1
+        self.draw_custom()
+
+    def draw_custom(self) -> None:
+        current_index = self.index(tk.END) + 1
+        if self.custom_index < current_index:
+            self.delete(self.custom_index, tk.END)
+        for name in sorted(self.app.core.custom_observers):
+            observer = self.app.core.custom_observers[name]
+            self.add_radiobutton(
+                label=name,
+                variable=self.observer,
+                value=name,
+                command=partial(self.app.core.set_observer, observer.cmd),
+            )
+
+    def click_edit(self) -> None:
+        dialog = ObserverDialog(self.app)
+        dialog.show()
diff --git a/daemon/core/gui/toolbar.py b/daemon/core/gui/toolbar.py
index da20948e..54fac126 100644
--- a/daemon/core/gui/toolbar.py
+++ b/daemon/core/gui/toolbar.py
@@ -15,6 +15,7 @@ from core.gui.graph.enums import GraphMode
 from core.gui.graph.shapeutils import ShapeType, is_marker
 from core.gui.images import ImageEnum
 from core.gui.nodeutils import NodeDraw, NodeUtils
+from core.gui.observers import ObserversMenu
 from core.gui.task import ProgressTask
 from core.gui.themes import Styles
 from core.gui.tooltip import Tooltip
@@ -184,6 +185,9 @@ class Toolbar(ttk.Frame):
         self.marker_frame = None
         self.picker = None
 
+        # observers
+        self.observers_menu = None
+
         # these variables help keep track of what images being drawn so that scaling
         # is possible since PhotoImage does not have resize method
         self.current_node = NodeUtils.NODES[0]
@@ -244,6 +248,7 @@ class Toolbar(ttk.Frame):
         self.runtime_select_button = self.runtime_frame.create_button(
             ImageEnum.SELECT, self.click_runtime_selection, "Selection Tool", radio=True
         )
+        self.create_observe_button()
         self.runtime_marker_button = self.runtime_frame.create_button(
             ImageEnum.MARKER, self.click_marker_button, "Marker Tool", radio=True
         )
@@ -381,25 +386,10 @@ class Toolbar(ttk.Frame):
         menu_button = ttk.Menubutton(
             self.runtime_frame, image=image, direction=tk.RIGHT
         )
+        menu_button.image = image
         menu_button.grid(sticky="ew")
-        menu = tk.Menu(menu_button, tearoff=0)
-        menu_button["menu"] = menu
-        menu.add_command(label="None")
-        menu.add_command(label="processes")
-        menu.add_command(label="ifconfig")
-        menu.add_command(label="IPv4 routes")
-        menu.add_command(label="IPv6 routes")
-        menu.add_command(label="OSPFv2 neighbors")
-        menu.add_command(label="OSPFv3 neighbors")
-        menu.add_command(label="Listening sockets")
-        menu.add_command(label="IPv4 MFC entries")
-        menu.add_command(label="IPv6 MFC entries")
-        menu.add_command(label="firewall rules")
-        menu.add_command(label="IPSec policies")
-        menu.add_command(label="docker logs")
-        menu.add_command(label="OSPFv3 MDR level")
-        menu.add_command(label="PIM neighbors")
-        menu.add_command(label="Edit...")
+        self.observers_menu = ObserversMenu(menu_button, self.app)
+        menu_button["menu"] = self.observers_menu
 
     def click_stop(self) -> None:
         """