I found this post online
https://devtalk.blender.org/t/update-property-when-active-tool-changes/11467/12
summary: maybe there is a mainline callback new
https://developer.blender.org/D10635
AFWS Jan '20
@kaio
This seem like a better solution. It’s kind of a mystery code, cause I
couldn’t figure out where you got that code info ,but then started
looking at the space_toolsystem_common.py file. kaio AFWS Jan '20
Just realized there might be a cleaner way of getting callbacks for
active tools using the msgbus. Since workspace tools aren’t rna
properties themselves, figured it’s possible to monitor the
bpy_prop_collection which changes with the tool.
The handle is the workspace itself, so shouldn’t have to worry about
keeping a reference. The subscription lasts until a new file is
loaded, so add a load_post callback which reapplies it.
Note this doesn’t proactively subscribe to workspaces added
afterwards. Might need a separate callback for that :joy:
import bpy
def rna_callback(workspace):
    idname = workspace.tools[-1].idname
    print(idname)
def subscribe(workspace):
    bpy.msgbus.subscribe_rna(
        key=ws.path_resolve("tools", False),
        owner=workspace,
        args=(workspace,),
        notify=rna_callback)
if __name__ == "__main__":
    ws = bpy.context.workspace
    subscribe(bpy.context.workspace)
# Subscribe to all workspaces: if 0:
    for ws in bpy.data.workspaces:
        subscribe(bpy.context.workspace)
# Clear all workspace subscriptions if 0:
    for ws in bpy.data.workspaces:
        bpy.msgbus.clear_by_owner(ws)