How can I track who pushes every button in my HMI?

I need to track every single toggle that happens in my HMI individually. Each person has a individual log in.

Every single button push, no such mechanism exists.

Every button push that writes to a tag, enable project auditing:

1 Like

well, you could have every button action inherit from a global script that got current user and wrote to a DB?

Darn I was hoping I could have all my buttons tracked. I cannot do one by one my HMI is to extense

You can also add entries into the audit log yourself with system.util.audit(), all of that methods parameters are optional and will auto populate for you, like the current session user, timestamp etc.

system.util.audit | Ignition User Manual

If you have an extensive interface and this is a major rework, perhaps consider using custom views for things like this next time. you can have a view that is nothing but a button that will log the action, send a message, manage permissions etc. Then adding functionality is only done in one place. We have three or four different buttons like this for different purposes like page navigation and equipment control. Page nav has alarm aggregation built in, device control has logging and permissions built in etc etc.

2 Likes

Are the buttons writing to tags? Or a mixture of that and other things?

This might be a dumb question… but I wonder if there's any way to decorate event handler functions?

You could potentially use vs code with find and replace for event handler code to add an audit log function call, searching all views

1 Like

How is the logic of your push buttons? Is all your business logic on the extension function or do you call a function immediately? This is one of the main organizational reasons to make all events a one liner to a function. If your button calls a function immediately, then you can use something like this

from functools import wraps

def getFullFunctionName(fn):
    try:
        fnPath = "{}.{}".format(fn.func_code.co_filename.split(':')[1].replace('>',''), fn.__name__)
    except:
        fnPath = fn.__name__
    return fnPath

def audit(fn):
    """
    Logs the params.  Always logs
    More suitable for button presses.
    """
    @wraps(fn)
    def wrap(*args, **kwargs):
        funcName = getFullFunctionName(fn)
        system.util.audit("Function:{} args:{} kwargs: {}".format(funcName, str(args), str(kwargs)))
        result = fn(*args, **kwargs)
        # Or wait until here and you can audit args, kwargs and result
        return result            
    return wrap

Then your business logic can be

@audit
def doSomething():
    pass

and your button would call the doSomething() function, and this would audit the args and kwargs of the function (good to know) and your system.util.audit would take care of the rest ie what user at what timestamp. So all you would have to do is bolt on a @audit onto all the business functions you care to audit.

This would not tell you what particular button (not sure the use of that anyways) but assuming that only 1 or a handful of buttons can trigger the same business logic (and if there are more than 1 button trying to do the same business logic you really should be doing a function call anyways to avoid having differing versions of the logic) it should be easy to trace out.

4 Likes