How to track which views a Designer user opens without modifying them?

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.

maybe system.util.audit | Ignition User Manual when open?

You cannot capture this. There's no event emitted by any system at any layer that you could watch for.

ok 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.

I was thinking you might also be able to hook into the designer via java to do it... We're back to hacking at things again.. haha

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

Thanks a ton, man! I really appreciate the time and effort you put into this. Your solution works perfectly.

Points at sign.
OP, can you maintain this shiny new pile of technical debt if (when) it breaks across a major or minor Ignition upgrade?

Maybe not, but Claude can :face_with_tongue: 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.

You've exceeded your token usage limit. Resets in 4hrs 59 min.

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. :person_shrugging:

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.