Audit.Changed
-------------

Log record change.

| Component | Version | macOS | Windows | Linux | Server | iOS SDK |
|---|---|---|---|---|---|---|
| [Audit](component_Audit.md) | [2.8](newinversion28.md) | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes |

MBS( "Audit.Changed"; TimeStamp; TableName { ; FieldsToIgnore...; ExtraFields... } ) 

**MBS**( **"Audit.Changed";** /\* Log record change. \*/  
**$TimeStamp**; /\* Pass here the timestamp field you added for auditing to the table.  
This field is passed here to trigger the calculation, but the value is not used. Must be a timestamp.e.g. AuditTimeStamp \*/   
**$TableName**; /\* The name of the table.  
Or the table occurrence if needed.  
  
With 10.2 optionally as second value the name of the audit log table unless you take the default AuditLog.e.g. "Firma¶MyAuditLog" \*/   
**$FieldsToIgnore...**; /\* Optional; A list of field names to ignore.   
Global fields and those set with [Audit.SetIgnoredFieldNames](AuditSetIgnoredFieldNames.md) are always ignored.e.g. "myField" \*/   
**$ExtraFields...**) /\* Optional; Custom fields to set.  
Pass in field name followed by "|" character and a value.  
Field type can be text or number.e.g. "ScriptName|" &amp; $ScriptName \*/ 

### Parameters

| Parameter | Description | Example | Flags |
|---|---|---|---|
| TimeStamp | Pass here the timestamp field you added for auditing to the table.   This field is passed here to trigger the calculation, but the value is not used. Must be a timestamp. | AuditTimeStamp |  |
| TableName | The name of the table.   Or the table occurrence if needed.      With 10.2 optionally as second value the name of the audit log table unless you take the default AuditLog. | "Firma¶MyAuditLog" |  |
| FieldsToIgnore... | A list of field names to ignore.    Global fields and those set with [Audit.SetIgnoredFieldNames](AuditSetIgnoredFieldNames.md) are always ignored. | "myField" | Optional |
| ExtraFields... | Custom fields to set.   Pass in field name followed by "\|" character and a value.   Field type can be text or number. | "ScriptName\|" &amp; $ScriptName | Optional |

### Result

Returns 1.

### Description

Log record change.  
In order to setup this for a table, please add two fields to the table. First a field called AuditTimeStamp which is of type timestamp. In the options enable in the Auto-Enter tab the option to set a new timestamp on modification. Next create a new field AuditState and make it a calculated value with the calculation MBS( "Audit.Changed"; AuditTimeStamp; TableName ). The Field "AuditTimeStamp" can be renamed to something like "sAuditTS" but has to be correctly referred to and should be included in the "[Audit.SetIgnoredFieldNames](AuditSetIgnoredFieldNames.md)" call if changed. By passing here an auto entered modification timestamp you make sure the plugin is informed about all changes to this table. Please uncheck the checkbox for "Do not replace existing value of field (if any)".  
  
For logging you need a table named AuditLog with a few fields. Required are fields named FieldName, FieldHash, TableName, RecordID. Optionally you can add more fields: FieldValue, FieldOldValue, FieldType, UserName, IP, CurrentTimestamp, TimeStamp, CurrentTime, CurrentDate, Action, CurrentHostTimeStamp, PrivilegeSetName, AccountName, LayoutNumber, ApplicationVersion, FileName, HostApplicationVersion, HostName, HostIPAddress, LayoutName, PageNumber, LayoutTableName, TableID, FieldID, CurrentTimeUTCMilliseconds, ScriptName and WindowName.   
The plugin will fill those fields with values evaluated from Get() function. FieldOldValue is only filled if we find an older log entry for the field based on the hash. With 4.2 plugin you can also use field Platform to know if plugin was executed on server or client.  
  
You can get access of a record logged if you use a script tigger to set the AuditTimeStamp field with a new timestamp whenever a record is loaded.  
  
This functions work even with separated files where data and layouts are in separated database files. The AuditLog table can be in a separated file as long as the plugin can can find a table occurence named "AuditLog", referencing to the original table which may be located in another FileMaker file and a layout based on this table occurence, named "AuditLog", to write into the log.  
  
The two fields AuditTimeStamp and AuditState can have different names. In that case we recommend to call [Audit.SetIgnoredFieldNames](AuditSetIgnoredFieldNames.md) in order to have the plugin ignore those fields. Or pass the field names to this function.  
  
To get all your existing records introduced to this Audit Function, move over all records in a loop in a script and call Audit.Changed to log the current one. This helps to fill the FieldOldValue field.  
And finally if you like, you can even built yourself an undo mechanism by restoring changes.  
  
On FileMaker 10 the [Audit](component_Audit.md) functions only work if tables and base tables have same name. Also we can't record FieldID or TableID on FileMaker 10. For FileMaker 11 and 12 everything works nice.  
  
In the fields to ignore parameters you can pass extra values "FieldName|Value" to assign special values automatically to your fields. As this parameter can be build with a calculation, you can query variables or other tables for information you want to log. With plugin version 7.2 and newer this works for number fields in addition to text fields.  
  
Table names are case sensitive. If you change case of a table name, the fields may be logged again.  
With plugin version 4.4 or later you can use \* on the end of the name to match all names starting with same text.  
  
Indexes in the AuditLog table help to speedup the queries internally made by plugin. Especially indexes for the fields FieldHash, FieldName, RecordID and TableName.  
  
Version 8.5 can use either FieldName or FieldID in AuditLog table to identify the field. For the value we prefer to use FieldHash, but if you have no such field, we use FieldValue. AuditLog field list is now queried via SQL instead of using a layout. So with version 8.5 the AuditLog layout is optional.  
  
If there is a failure in the generated SQL, you may see it with [FM.ExecuteSQL.LastErrorMessage](FMExecuteSQLLastErrorMessage.md) and [FM.ExecuteSQL.LastSQL](FMExecuteSQLLastSQL.md) functions. The [audit](component_Audit.md) functions relay on the permissions to make SQL queries on your tables.  
  
If CurrentTime field is of type time, timestamp or date, we use CURRENT\_TIME, but otherwise Get(CurrentTime).  
If Timestamp field is of type time, timestamp or date, we use CURRENT\_TIMESTAMP, but otherwise Get(CurrentTimestamp).  
If CurrentDate field is of type time, timestamp or date, we use CURRENT\_DATE, but otherwise Get(CurrentTimestamp).  
If CurrentHostTimeStamp field is of type time, timestamp or date, we use CURRENT\_TIMESTAMP, but otherwise Get(CurrentHostTimestamp).  
If CurrentTimestamp field is of type time, timestamp or date, we use CURRENT\_TIMESTAMP, but otherwise Get(CurrentTimestamp).  
LayoutNumber, CurrentTimeUTCMilliseconds, TableID, RecordID or FieldID can be stored as text or number depending on field type.  
  
This function takes variable number of parameters. Pass as much parameters as needed separated by the semicolon in FileMaker.  
Please repeat FieldsToIgnore and ExtraFields parameters as often as you need.  
### Examples

Log record on changes:

 MBS ( "Audit.Changed"; MyTable::AuditTimeStamp ; "MyTable" )  
Log record on changes except fields fullname and zipCity:

 MBS ( "Audit.Changed"; MyTable::AuditTimeStamp ; "MyTable"; "fullname"; "zipCity" )  
Log change and pass value for custom log field "InsideScript" with value of variable:

 MBS ("Audit.Changed"; AuditTimeStamp; "Audit"; "InsideScript|" &amp; $$InsideScript )  
Log changes and pass custom GUID field while also checking a global variable to disable auditing for batch imports:

 If ($$AuditDisabled ; 0;   
 MBS ("Audit.Changed"; AuditTimeStamp; "Audit"; "GUID|" &amp; GUID)  
 )  
Run Audit.Changed with list of fields in a global field in the table:

 Evaluate("MBS (\\"Audit.Changed\\"; GetAsTimeStamp(\\"" &amp; Events::AuditTimeStamp &amp; "\\"); \\"Events\\"; \\"" &amp; Substitute(Events::AuditFields ; "¶"; "\\"; \\"") &amp; "\\")")  
Run Audit with GetFieldName with v8.3 or newer:

 MBS ("[Audit.Changed2](AuditChanged2.md)"; // call with positive list  
AuditTimeStamp; // the timestamp field to trigger this  
"Audit"; // the name of table  
GetFieldName ( SomeText); // the fields to check  
GetFieldName ( SomeNumber);   
GetFieldName ( SomeTime);   
GetFieldName ( SomeTimeStamp);   
GetFieldName ( SomeContainer);   
"InsideScript|" &amp; $$InsideScript ) // and we pass an extra field with global variable  
Run Audit with Perform Script on server for FileMaker Go:

 # Audit on server   
  
\# Audit on server in file Audit   
   
\# give FileMaker Go some time to save   
Pause/Resume Script \[ Duration (seconds): ,5 \]   
\#   
\# get parameter with layout and record id   
Set Variable \[ $Param ; Value: Get(ScriptParameter) \]   
Set Variable \[ $LayoutName ; Value: GetValue($Param ; 1) \]   
Set Variable \[ $ID ; Value: GetValue($Param ; 2) \]   
Set Variable \[ $UserName ; Value: GetValue($Param ; 3) \]   
\#   
\# go to record   
Go to Layout \[ $LayoutName ; Animation: None \]  
Perform Find \[ Restore \]  
\# with MyTable::ID = $ID   
\#   
\# log changes   
Set Variable \[ $r ; Value: MBS ("Audit.Changed"; Audit::AuditTimeStamp ; "Audit"; "ServerUserName|" &amp; $UserName ) \]   
Exit Script \[ Text Result: $r \]   
  
\# Trigger above script for Audit on server in On Record Commit trigger   
   
Set Error Capture \[ On \]  
\#   
\# check for missing plugin, e.g. on FileMaker Go   
If \[ GetAsText(MBS ("Version")) = "?" \]   
 Perform Script on Server \[ Specified: From list ; “Audit on server” ; Parameter: Get(LayoutName) &amp; ¶ &amp; MyTable::ID &amp; ¶ &amp; Get(UserName) ; Wait for completion: Off \]  
End If  
Log change with custom fields to log relation to Company and Account:

 MBS ("Audit.Changed";   
// timestamp field to trigger this  
AuditTimeStamp;   
// current table to track  
"Customers";   
// fields to Skip  
"SummaryTotal";   
"FullName";  
// custom field with an Audit Transaction ID  
"TransactionID|" &amp; Get(UUID);   
// and two fields to relate to matching company and account  
"CompanyID|" &amp; Company::ID ;  
"AccountID|" &amp; Account::ID )  
Log only changes and skip Audit for new records:

 If (Get ( RecordOpenState ) = 1 ; 0;   
MBS ("Audit.Changed"; AuditTimeStamp; "Audit"))  
// Skip audit for new records  
### See also

- [Audit.Backup](AuditBackup.md)
- [Audit.Changed2](AuditChanged2.md)
- [Audit.SetEnabled](AuditSetEnabled.md)
- [Audit.SetIgnoredFieldNames](AuditSetIgnoredFieldNames.md)
- [Audit.Statistics](AuditStatistics.md)
- [FM.ExecuteSQL](FMExecuteSQL.md)
- [FM.ExecuteSQL.LastError](FMExecuteSQLLastError.md)
- [FM.ExecuteSQL.LastErrorMessage](FMExecuteSQLLastErrorMessage.md)
- [FM.ExecuteSQL.LastSQL](FMExecuteSQLLastSQL.md)
- [Version](Version.md)

### Release notes

- **Version 14.1**
    - Changed [Audit.Changed](https://www.mbsplugins.eu/AuditChanged.shtml) to ignore empty field names.
- **Version 12.1**
    - Fixed bugs in [Audit.Changed](https://www.mbsplugins.eu/AuditChanged.shtml) when using repetition fields.
- **Version 12.0**
    - Fixed handling of PageNumber field for [Audit.Changed](https://www.mbsplugins.eu/AuditChanged.shtml) functions.
- **Version 10.4**
    - Fixed a crash in [Audit](https://www.mbsplugins.eu/component_Audit.shtml) functions when querying GetFieldID internally. Affects [Audit.Backup](https://www.mbsplugins.eu/AuditBackup.shtml), [Audit.Backup2](https://www.mbsplugins.eu/AuditBackup2.shtml), [Audit.Changed](https://www.mbsplugins.eu/AuditChanged.shtml), [Audit.Changed2](https://www.mbsplugins.eu/AuditChanged2.shtml), [Audit.Delete](https://www.mbsplugins.eu/AuditDelete.shtml) and [Audit.Delete2](https://www.mbsplugins.eu/AuditDelete2.shtml) functions.
    - Fixed an issue where [Audit.Changed](https://www.mbsplugins.eu/AuditChanged.shtml) would rebuild the table cache too often.
    - Improved [Audit.Changed](https://www.mbsplugins.eu/AuditChanged.shtml) and related to only query table list once per call.
- **Version 10.2**
    - For [Audit.Changed](https://www.mbsplugins.eu/AuditChanged.shtml) and [Audit.Changed2](https://www.mbsplugins.eu/AuditChanged2.shtml) you can now customize AuditLog table name. The table name parameter can be a list and include first the table name for the table to check and second the name of the audit table name. If second is empty, we default to AuditLog.
- **Version 10.1**
    - Changed [Audit.Changed](https://www.mbsplugins.eu/AuditChanged.shtml) and related to work with PageNumber and LayoutNumber as numeric fields.
- **Version 8.5**
    - Improved [Audit.Changed](http://www.mbsplugins.eu/AuditChanged.shtml) and related to set last error for SQL calls.

### Example Databases

- [Audit/Audit](https://www.mbsplugins.eu/MBS-FileMaker-Plugin-Examples/Audit/Audit.shtml#1298FieldAnchor_)

### Blog Entries

- [MBS FileMaker Plugin, version 14.1pr6](https://www.mbsplugins.de/archive/2024-03-07/MBS_FileMaker_Plugin_version_1/monkeybreadsoftware_blog_filemaker)
- [Configure Audit functions in MBS Plugin](https://www.mbsplugins.de/archive/2022-06-10/Configure_Audit_functions_in_M/monkeybreadsoftware_blog_filemaker)
- [MBS FileMaker Plugin, version 12.1pr2](https://www.mbsplugins.de/archive/2022-02-08/MBS_FileMaker_Plugin_version_1/monkeybreadsoftware_blog_filemaker)
- [MBS FileMaker Plugin, version 11.6pr4](https://www.mbsplugins.de/archive/2021-12-22/MBS_FileMaker_Plugin_version_1/monkeybreadsoftware_blog_filemaker)
- [MBS FileMaker Plugin, version 10.4pr5](https://www.mbsplugins.de/archive/2020-08-24/MBS_FileMaker_Plugin_version_1/monkeybreadsoftware_blog_filemaker)
- [Perform Script on Server with Audit for FileMaker Go](https://www.mbsplugins.de/archive/2020-08-18/Perform_Script_on_Server_with_/monkeybreadsoftware_blog_filemaker)
- [Audit with MBS FileMaker Plugin](https://www.mbsplugins.de/archive/2017-01-07/Audit_with_MBS_FileMaker_Plugi/monkeybreadsoftware_blog_filemaker)
- [Audit with MBS Plugin and FileMaker Server, works with FileMaker go!](https://www.mbsplugins.de/archive/2014-05-13/Audit_with_MBS_Plugin_and_File/monkeybreadsoftware_blog_filemaker)
- [Audit Tip for Importing](https://www.mbsplugins.de/archive/2012-08-24/Audit_Tip_for_Importing/monkeybreadsoftware_blog_filemaker)
- [Introducing Audit Plugin Functions for Filemaker](https://www.mbsplugins.de/archive/2012-08-01/Introducing_Audit_Plugin_Funct/monkeybreadsoftware_blog_filemaker)

### FileMaker Magazin

- [Ausgabe 4/2017, Seite 40](https://filemaker-magazin.de/neuigkeit/3946-Appetithappen-FMM_201704)

This function checks for a license.

Created 18th August 2014 , last changed 25th February 2026

  
[Audit.BuildCaches](AuditBuildCaches.md) - [Audit.Changed2](AuditChanged2.md)

[HTML Version](AuditChanged.shtml)