We are tracking user activity in our audit log idaa_t_audit_event. We have successfully implemented page visit tracking for Perspective sessions using a custom prop on the Header view with an onChange script. We can also see resources modified events in the audit log when a Designer user saves/edits a view.
When a Designer user simply opens a view to read it without making any changes, nothing gets logged in the audit table. We need to capture this read-only access as well.
Is it possible ?
Thanks.
You could log this using Periscope's Client Resource feature.
All Client Resources loaded and run on page load/refresh (including in the designer).
You could create a Client Resource module that calls an API on every page load (initial load + listen for future changes) and passes Page/Session telemetry information.
This seems to work. Run this in the script console. To roll this out automatically, call the script from a Vision Client Tag's value change script event handler; set it to an expression tag with expresion: now(0) to make it change once on load. You need to have Vision module installed but it doesn't need to be licensed.
Note: Claude.ai wasn't able to get it working with events, so this periodically checks every 500ms for new views opened.
try:
timer.stop()
except: pass
from java.awt import Window
from javax.swing import Timer
from java.awt.event import ActionListener
ctx = None
for window in Window.getWindows():
if 'Designer' in window.getTitle():
ctx = window.getContext()
break
rem = ctx.getResourceEditManager()
# Get the openResources field
openResourcesField = None
for f in rem.__class__.getDeclaredFields():
if f.getName() == 'openResources':
f.setAccessible(True)
openResourcesField = f
break
previousPaths = set()
class OpenViewWatcher(ActionListener):
def actionPerformed(self, e):
try:
current = openResourcesField.get(rem)
currentPaths = set(str(p) for p in current)
newlyOpened = currentPaths - previousPaths
for p in newlyOpened:
if 'perspective' in p.lower() or 'views' in p.lower():
print "View opened:", p
system.util.audit(
action='designer view opened',
actionTarget=p,
actionValue=None,
auditProfile='TestAudit',
actor=system.vision.getUsername(),
actorHost=system.vision.getExternalIpAddress()
)
previousPaths.clear()
previousPaths.update(currentPaths)
except Exception as ex:
print "Watcher error:", ex
watcher = OpenViewWatcher()
timer = Timer(500, watcher)
timer.setRepeats(True)
timer.start()
print "Watching for opened views (500ms poll). Run timer.stop() to cancel."
Wow, that really works thank you! This is exactly the kind of solution I was looking for.
I have one follow-up question. My goal is to understand Designer usage across our organization. We have around 52 Ignition projects and 1,000+ Designer users, and I'd like to track which Perspective views each user opens.
Would it be possible to capture the Designer username along with the view path, so the audit (or database) records something like:
User A β Perspective/Views/Main
User A β Perspective/Views/Reports/Daily
User B β Perspective/Views/Production/Overview
Ultimately, I'd like to generate a report showing which users are opening which views and how frequently, on a per-user, per-view basis.
This should already do exactly this. Ignore the system.vision functions. Imo these shouldn't be hidden in the Vision module since these equally apply to the designer. They are just Java environment functions, which the designer is itself. I assume that's where your questions come from? Ie system.vision.getUsername() gets the user logged into the designer if it's run inside the designer
Unless your 52 projects inherit from the same global project where you can add the vision client tag to (and you're not using Vision - if you're using Vision then the client tags would most certainly be overridden in each leaf project), you would have to add the vision client tag to each project indivudally
Note: I didn't check if the project name the audit record logged under was correct, it should come through properly, but you need to check that
Note also that the script would capture multiple opens while the designer is open. As in 2 records for the same view if a user opens it, closes it, and reopens it
Maybe not, but Claude can but really, this particular thing sounds more something to gain insight from in the short term. I doubt it's of significant importance particularly over the long term.
OP's multiple threads about auditing lead me to the exact opposite impression. I feel like they've got a higher up breathing down their neck with a bunch of requirements, and they're building a house of cards inadvertently.
Nick's code is already wrapped in exception handling, so I doubt it would ever make the designer unusable if something failed, but even so, I'd recommend modifying the client tag that applies this to include some sort of way out just in case somebody expands this later and accidentally introduces a breaking change. I could imagine scenarios where faulty initial change scripts of this nature could brick the designer.
On the client tag, it could be as simple as:
# Exclude at least one admin account
# ...so it can access an unmodified version of the designer if need be.
if username not in ["recoveryAdmin", ...]:
# Apply patches
...and hopefully the management team that is pushing for these kinds of metrics doesn't end up using them to lay off those who understand how this client tag patch is applied.