Error trapping advice

TLDR: I'm adding an "errors" table to my database, and want to make sure:

a) it doesn't get stuck in a loop of errors during import
b) I'm not creating overly complex code

Advice/best practices would be appreciated.

Details:
So I have an import which keeps failing. There doesn't seem to be a way to know which "167" out of "257" records had errors or what those errors are, either the import works or it doesn't work. A few people have recommended importing into a separate table and then manually moving over the data with a looping script which goes through the records and sets all the fields. I'd been resisting because it seems like there's more chance for human error (mine) and it's just more "crud", but there are just too many times where imports don't happen and I'm not aware of them, so I'm finally breaking down and doing it.

Here's a simplified version of my merge script (obviously I'd have a lot more fields to set)

Screenshot 2023-10-12 at 9.37.51 AM

One concern I have is because it looks for "LastError" if I have an error on record 2 (for example) will it then keep logging every record? Do I need to turn error capture on and off or do something else to reset the error? I feel like I'd need to do something.

I'm hoping to streamline my error code so I don't have to pass in all this in a JSON file every time I have an error:

JSONSetElement (
""
; ["LastErrorLocation" ; get(LastErrorLocation) ; JSONString]
; ["LastErrorDetail" ; get(LastErrorDetail) ; JSONString]
; ["LastError" ; get(LastError) ; JSONString]
; ["Layout" ; get(LayoutName) ; JSONString]
; ["Notes" ; "" ; JSONString]
)

I created a custom function where I pass in the notes (ErrorLog("these are notes") and the custom function spits out the JSON data for me. When I put the JSON in a variable it looks fine, but when I use that as the parameter it doesn't work. Do I have to do something tricky to get Filemaker to actually perform the JSONSetElement?

With the execution of each script step that "does something", the value of Get( LastError ) will be updated with a value corresponding to the outcome of the most recently executed step. When I say "does something", I'm speaking of pretty much most of the script steps with the exception of control steps such as "If", "Else If", "Loop", etc..

So, this means that you should be able to set aside concerns about an error that happens in one step continuing to persist in Get( LastError ) during other parts of your script. Perhaps a way to think about Get( LastError ) that could help make this more intuitive would be to think of it as "Get result about last script step that executed" -- not nearly as succinct, but maybe more clear.

As for:

JSON and JSONSetElement and a custom function that uses JSONSetElement should all work as expected when used in the Script Parameter calculation dialog. I'm having a difficult time thinking of any exception to this. I'd be open to hear/see more details about how this is playing out in the scenario that you are dealing with, or perhaps someone else will think of something obvious that I happen to be missing...

Also, further on Error Trapping:

I am a big fan of implementing error detection and handling within scripts -- my personal feeling is that it pays for itself very well in terms of preventing large-scale data mishaps that I've seen happen in solutions which did not have error trapping, and which allowed for errors to go undetected until such a time when the problem had really snowballed into something much bigger than it would have had to be.

Notable is that within a short number of hours, @Bobino will be giving a presentation that sounds particularly relevant:

Also, I believe that @jwilling has invested a lot of time/energy into considering effective ways to do error trapping. I'm deliberately tagging him here, in case he has something to offer in response to your post...

1 Like

thanks @steve_ssh for adding a reference to the live presentation that will take place shortly.

Indeed, even if tonight's discussion will not get into error logging, we will clearly be talking about error handling and the patterns involved along with some custom functions that we will be looking into.

Feel free to take part to this discussion. The meetup link above should be all you need.

As you have mentioned, @jwilling has been looking at how best to tackle this also. I hope he will be attending and sharing with all of us what he considers best practice when it comes to error handling.

1 Like

Unfortunately I saw @steve_ssh 's hint too late. Is there a recording of the presentation/meeting?

go to Youtube in a few days, when the video is posted:

You may want to subscribe to the channel and click the bell, so you get notified for new videos.

3 Likes

All this info is great. Thank you. Also I figured out the JSONSetElement problem I was having. I was actually turning the whole thing into a text string, instead of letting it run in the function. IDK what I was thinking. Derp... I'll watch the video when I get a minute. Helpful tip!

1 Like

For anyone interested, the recording of that meeting has been published: https://www.youtube.com/watch?v=muhK5AGVb7o

5 Likes

[1] I would put this calculation...

JSONSetElement (
""
; ["LastErrorLocation" ; get(LastErrorLocation) ; JSONString]
; ["LastErrorDetail" ; get(LastErrorDetail) ; JSONString]
; ["LastError" ; get(LastError) ; JSONString]
; ["Layout" ; get(LayoutName) ; JSONString]
; ["Notes" ; "" ; JSONString]
)

...into a Custom Function (CF) to DRY out you code and make it possible to update it only once per File. @errorObject ( "notes" ) would be a possible @CF_name (param) signature.

I would add get ( ScriptName ) and a CF @scriptID // as ScriptNames can change and/or be duplicates. Errors are generated from within a Script and you will want to know which Script. (Passing the Call Stack along is a topic for another day.)

The CF @scriptID code below could be improved and added to your @ErrorObject CF @scriptID
// Tony White Designs, Inc. 2016-10-29_v1
// Called from within a script.

Let (
[
~the_ScriptNames.padded = "¶" & ScriptNames ( "" ) & "¶" ;
~a_ScriptName.padded = "¶" & Get ( ScriptName ) & "¶" ;
~the_position = Position ( ~the_ScriptNames.padded ; ~a_ScriptName.padded ; 1 ; 1 ) ;
~value_number = ValueCount ( Left ( ~the_ScriptNames.padded ; ~the_position ) ) ;
~the_ScriptIDs = ScriptIDs ( "" ) ;

~scriptID = GetValue ( ~the_ScriptIDs ; ~value_number )
] ;
~scriptID // return
)

There are a number of Get ( Functions ) and other pieces that could be picked up and added from within your LogError Script (assuming same File for scope) including get(LayoutName), CF @ getLayoutID.sameFile, etc.

All off this is ideally passed to a HelpRequest File that adds more Get (Function) info (scoped to the session) and handles notifications and tracking.

Edit: You might want to add these
Get ( ActiveModifierKeys )
Get ( AllowAbortState )
Get ( CurrentExtendedPrivileges )
Get ( CurrentPrivilegeSetName )
Get ( ScriptParameter )
Get ( TriggerKeystroke ) // maybe
Get ( TriggerModifierKeys ) // maybe
Get ( ScriptResult )