In last weeks “part 1” post, I introduced why I needed to log faults and information from Salesforce Visual Workflows which I have been writing . I recommend reading that post before digging into the detail here.
With a custom object in which to store any fault or status messages I was able to use a simple flow component to create a new record from inside any flows which I wrote. I enhanced this pattern by having several flavours of flow to log different information.
LogFault is my flow which I wire up to fault connectors in every flow that I write. When I just want to send application messages, I use my LogInfo and LogInfo flows.
LogFault, LogError & LogInfo Flows
All three logging flows share the same structure, here is the LogFault flow.
There are three variables.
Input only, passes the message from the calling flow.
Input only, passes a combination of the calling flow’s Id and name (as explained in part 1).
Output only, returns the Id of the created process log record to the calling flow.
The formula to FormatDefintionURL takes the flow’s Id and appends it to the Salesforce URL to make a link which can be clicked to quickly access the flow definition when I am investigating any problems.
Here is how the values are mapped to the record create component as part of the call.
The value for Type__c, the type of message is the only thing which changes between the different versions. LogError flow sets the type to be “Error” and LogInfo is “Info”
That is all that is needed to create the flow. Don’t forget to make the start element with the green arrow.
Because there is only 1 element in the flow, the editor will give a warning when the flow is saved. It’s okay, it will still run.
Using The Log Flows
Now the LogFault flow (and it’s siblings, LogError and LogInfo) have been created they can be used in new and existing flows. I actually went back to all the flows in our production org and updated them to add not only fault handling, but also information messages. I was very glad that I did as it helped me solve a number of logic problems and field permission errors.
Taking the idea of adding logging to an existing flow, lets start with the following very simple flow which checks if a contact exists, and if not creates a new one before returning the Id of the new or existing contact.
This flow has two data access components, if a fault is raised by them nothing is reported and nobody is any the wiser, save for maybe the original author that wrote the flow who might get a system generated email. We can do better than this!
The log flows are available in the palette and can be added to the flow.
The flow is transformed! It still does the same basic function, but we have two very important additional features. The fault connections are wired up for the two data access components, now if there is a problem we will have a record of it. There is also a record of the beginning middle and end of the flow’s progress. This type of information is invaluable when troubleshooting a flow.
Here is the information which the flow logs when it is run under different conditions.
Looking at a single record, all the captured fields can be seen.
My favourite feature is the URL field as it saves me so much time to be able to jump to the flow definition when reviewing the logs. And because the process log is a Salesforce custom object I am able to use it in reports, dashboards and I’ve even hooked it up to a push topic on the Streaming API. But that’s another story for another post.
I hope that these two posts have provided ideas around instrumenting your business processes, and I am sure that there is a lot more which can be done to build on this foundation.
Matthew – Really interesting post. I’m trying to implement in my org, but I’m not sure where the Origin__c field gets its value. I’ve read your post over a few times and you explain that Flow Name and Flow URL are put together from parsing the data in the Origin__c field, but I’m not sure where the Origin__c field gets its value in the first place. Can you elaborate?
It’s as basic as looking up the values and pasting them in. It was the only way that I could find to source to Id of the Flow, there is no hidden API. I will add a post to make this clearer.
How are you capturing the ID and Name of the triggering flow in order to pass it to the FlowName variable on the LogFault sub-flow?
Yes, I skipped over that bit too quickly. It’s the Flow’s Id from the browser URL bar, pasted into a formula field (in case I wanted to do any further manipulation later).