Written by

Architect at UnitedHealth Group (Optum)
Question Tirthankar Bachhar · Oct 27, 2016

How to track the last modified by user name

Hi,

Is there any way to track the 'last modified by' cache user name and datetime of last modification for a class or routine definition [Track Last Code Changes]?

Thanks,

Tirthankar

Comments

Ben Spead · Oct 27, 2016

You can add logic in %OnAfterSave() for your object which will grab the object ID, $Username and the timestamp and tuck them away in an auditing table somewhere.  Alternatively you could add LastChangedBy and LastChangedTimestamp properties to your object and then populate them inside of %OnAddToSaveSet() (this is probably the most straightforward way to do it).

Hope that helps!

0
Tirthankar Bachhar  Oct 27, 2016 to Ben Spead

Hey, thanks for your response.

The solution you gave is to track any changes in data.

But, what I was looking for was, how do we track any changes in class definition [Code Changes made].

0
Ben Spead  Oct 27, 2016 to Tirthankar Bachhar

Sorry - I missed that.

Getting the "When" is easy - there is a timestamp in the header of the generated .INT code showing when the source was last compiled.  E.g:

 ;Sample.Address.1
 ;(C)InterSystems, generated for class Sample.Address. Do NOT edit. 10/27/2016 09:12:38AM
 ;;7A2F686C;Sample.Address
 ;
However the "Who" might prove to be more challenging. You might be able to accomplish this with a Method Generator that records the $Username and timestamp for access via a method or parameter?  See http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…

0
John Murray · Oct 27, 2016

For a class definition you can get the timestamp of last change from the TimeChanged property of the %Dictionary.ClassDefinition instance for the class.

For a routine, the TimeStamp property of its %Library.Routine instance is what you want.

But AFAIK the associated username isn't recorded automatically. You could use the server-side source control class interface to record this kind of thing, but it relies on whatever is making the change actually collaborating with that interface.

Do you use any form of source control?

0
Eduard Lebedyuk · Oct 27, 2016

The correct way to accomplish that is to use source control and CI:

  • Developers push code into a central repository
  • CI system gets the code, tests it and deploys to the server
0
Evgeny Shvarov  Oct 27, 2016 to Eduard Lebedyuk

Agreed with Eduard. Keep all your code in the repository and you will know who did this and that and never loose the history of changes.

0
Alexey Maslov · Oct 28, 2016

Using a repository is a good idea for sure, but what about a solution that can help even if an 'intruder' had bypassed it and changed a class, e.g., on production server? Here is one which answers who changed SomeClassName.CLS; this code can be executed in "%SYS" namespace using System Management Portal/SQL:

SELECT DISTINCT TOP 1 s.UTCTimeStamp, s.OSUsername, s.Username, s.Description
FROM %SYS.Audit as s
WHERE s.Event='RoutineChange'
AND s.Description LIKE '%SomeClassName.cls%'
ORDER BY s.UTCTimeStamp desc

It's easy to adapt it for searching the same info for MAC, INT and INC routines.
Enjoy!

0
Evgeny Shvarov  Oct 28, 2016 to Alexey Maslov

Good point, Alexey!

If you are looking for the intruders, maybe also Auditing is the best solution to use?

0
Alexey Maslov  Oct 29, 2016 to Evgeny Shvarov

Certainly yes: SQL quering of Audit database (%SYS.Audit) won't help if Auditing is switched off.

0
Tirthankar Bachhar  Nov 4, 2016 to Alexey Maslov

Thanks so much for your help. This is what exactly I was trying to find. Thanks again Alexey.

0