An end user just noticed that if a tag has write permissions set on it and the tag is bidirectionally bound to a toggle switch (in Perspective for example), and a user who doesn't have the write permission tries to toggle the switch, it correctly doesn't write and shows a warning message. However if you check the audit log, there will be a "tag write" action for that tag and user indicating the write went through which is extremely deceptive and can destroy the credibility of the log.
Yes, I reproduced this problem on 8.1.48.
Did you open a support ticket?
Yes I did ![]()
Can you please provide an update and/or link to the support ticket? Iāve just encountered this same issue.
To me, this points to an issue in the UI or project configuration. The audit log shouldnāt be used as a source of verification that a write was successful, only that the write was attempted. In my opinion, that action SHOULD be recorded.
Fair about recording an attempt, but then a log for the rejection of the write should be present as well which I take it is not the case.
Perhaps. However, thereās a thousand ways that a write could āfailā. Tag permissions, provider permissions, service security, poor network connection to an end device, rejection by the end device, accepted but immediately overwritten in the end deviceā¦
Right but if we go with your idea that the attempt should be recorded no matter what (which I do agree with) what there must be some indication if it was not succesful otherwise @nminchin original point stands that the log becomes unreliable. Reason can be whatever, but tell me it didnāt go through. A lot of those reasons are probably catchable and recordable too, certainly permissions ones, and if its not then a āfailed write reason unknownā at least keeps the audit trail 100% truthful about what happened, user tried to write, something bad happened we donāt know what but the write didnāt go through. Without that it just looks like the user wrote when they didnāt.
Confirmation is covered by historization. Capturing write rejection reasons is near impossible, since some can be external. There's no replacement for proper use of try clauses and inspection of returned quality codes.
Sounds like the best thing to do is just write your own writeTags function that examines the result and audits failures appropriately and call that for all your tag writes instead? In scripts at least
Though that doesnāt really help in the OP case where it was due to tag binding on a UI component.
Are you saying if you have audit trails enabled without the historian module your SOL to create such a trail (user wrote and the confirmation of if the write went through or not)?
In my opinion, the first step is to update the UI to disallow the write in the first place. The user should know whether-or-not they have permission to write before they attempt to do so. Tags have a ā.CanWriteā property (value is unique per-client) and can be bound in the UI to disable the entry in the first place. Note that this doesnāt capture all possible scenarios as might be required from a proper audit trail (those previously listed, also tag deadband preventing a value update, floating point representation error after successful write, etc.).
Iāve not built a proper audit tool personally (despite my own empty threats to do so). But, I have spent enough time compiling data for other parties (managers, engineers, lawyers) that Iāve resolved that:
- Itās a difficult problem to solve for āall usersā & āall use-casesā.
- Iām grateful that I have too much data to work with, instead of not enough.
- Despite 1 & 2, Iām still frustrated every time I have to handle all of the useless data in the audit logs.
I agree to your point in regard to the UI not even being allowed to write and using a that to not allow a non-permissable user to even attempt to write.
Though as you said there are a ton of reasons something could fail not related to any permissions. So you could have a person who does have permissions try to wirte, it fails and the audit trail looks all good.
I personally donāt particulary care about why being logged to the audit trail for UI binding writes personally just if it failed because what I am I thinking about is getting a call to come in the day(s) after to check something out - Hey we pressed this button but the process didnāt start. If I look at the audit logs and see a tag write and nothing else what else can I interpret but that the tag was written to and something happened on the PLC side of things.
But If i see tag write and a failure (without any reason listed), I would start elsewhere - how is the opc-ua server, the ignition connection to the opc-ua, the network etc. I canāt say anything for certain just off the audit trail but it would help me not go on a wild goose chase immediately where I assumed the tag was written to when it was not.
Thats why I think even without auditing a reason if possible it would be nice to record a failure. Though unfortunately doesnāt seem feasible according to Phil.
Unsolicited, yet unapologetic tangent:
I do wish there were an optional argument on system.tag.write* functions which resembles the functionality of skipAudit arg on the system.db.runPrepUpdate function. I envision that this arg would give someone a better ability to build an audit system which matches their needs.
I believe @nminchin has a post about this feature request:
Psssssst! Not implemented!
![]()
I just tested and confirm that running the runPrepUpdate function with skipAudit=False DOES add an entry to the audit log. I also confirm that running the same script with skipAudit=True DOES NOT add an entry to the audit log.
I suppose there is some ambiguity in his statement:
Thereās a recent post on lack of audit w.r.t. named queries:
What scope were you calling from?
(I will obviously have to revisit this in my toolkit.)
Yeah, my earlier post was ambiguous. Calling scope matters.
DB functions from client/designer scope hit special RPC methods that "understand" the skipAudit flag.
Direct DB system function calls when you're already in gateway scope don't do anything with the skipAudit parameter.
Good to know! As can be assumed, I did execute from script console for my quick test above. Somewhat unrelated - but Iāve also confirmed audit entries via Database Query Browser (Designer) when query type is āUpdateā.