Trailhead: Event Log Monitoring

 

trailhead_module_shield_event_monitoringSay what?  Event Monitoring?  What’s that?

Winter ’15 delivered a little hidden gem – Event Log Monitoring (ELF).  ELF enables the ability to see a lot of the things that are happening in your org behind the scenes that you just could not answer before – such as:

“Did [x] download my customer list before quitting?”

“How fast is my Visualforce Page loading?”

“Who clicked on a record?”

“Holy moly!”

That’s honestly the only phrase that comes to mind when I’m staring at the new ELF files that I can access.  I can’t tell you how many times I’ve been asked just that first question above by my customers…and up until now all I’ve been able to do is offer future-looking convoluted technical solutions to prevent it from happening in the future.

Ok Andy – I’m not a developer and what I’ve read so far is full of something called “Workbench” and “JSON”.

That’s the best part!  Even though this is really an API-only feature, Salesforce and the community at large have created some great tools (even free in some cases) to help anyone take advantage of this critically important new feature.  *cough* Trailhead *cough*

Ok Andy – enough beaming, let’s get down to brass tacks.  How do I use this?

trailhead-emblemOk.  First things first – let’s start with the new Trailhead module on ELF!  Click here to get started.  “Why would I do Trailhead before just jumping in?” do you ask?  In my opinion, Trailhead is becoming the de facto “first stop” for Salesforce training.  The biggest benefits that Trailhead gives you with ELF are:

  1. Well written content
  2. Real-world examples
  3. In-depth yet contextually appropriate knowledge bullets
  4. “One step further” with great tools and visualizations for ELF

Let’s face it – ELF is not declarative-friendly; this is an API-only feature.  There is no standard UI interface for ELF, you download this data as an array of data and then have to make it useful through a number of visualization tools.  Trailhead takes this situation head-on and gives you INCREDIBLE tools such as Salesforce-ELF to easily retrieve the data you want without needing to write scripts and decipher REST in Workbench, and then visualization tools such (free) Cloudlock Event Monitoring Viewer to actually get you answers to burning questions.

Honesty time:  I read about ELF in the Release Notes, but I saw raw JSON responses and immediately shelved this as “wow, that’ll take some time to visualize…I’ll do that ‘later’.” When Trailhead released their module on ELF – I learned more in 45 minutes than I ever would have by following the release documentation and stumbling around on my own.

So, what are you waiting for?  Head over to the ELF module on Trailhead and start now!

How are you using ELF?  Sound off in the comments below or hit me on Twitter – @andyboettcher!

Advertisements

Creating a new Event or Task with prepopulated information

Here’s a fancy little trick I came up with the other day.  If you’re scouring Google for ideas on this – hopefully this helps you out.  *smile*

BUSINESS NEED:

In Salesforce, a user wants to be able to click a button from a Custom Object and create a new Task with pre-populated information according to a number of defined business rules.  Using good “best practice” process methodology and user interface design, we’ll want to do this quickly, with a minimal number of clicks, and giving a “cool factor” to the user.

*You could do this with ANY object by just changing around the objects and fields, but this is an example for a Custom Object I was working with.

MY INITIAL APPROACH:

Not wanting to reinvent the wheel, I Googled around a little bit to see if anyone had done this before.  The majority of what I found was manipulation of the HTTP GET string.  Workable?  Sure…but the minute Salesforce changes their form Ids, your code breaks.  Granted their Ids are pretty set, but I hate coding with a “what if” like that in my head.  I really hate fixing code I wrote months ago because “something changed”.

MY RE-WORKED APPROACH:

A combination of custom objects, custom settings, APEX, and Visualforce.  At first blush it may seem a little over-engineered, but read on and you’ll see why it’s the *RIGHT* solution.

  • Custom Object
    • “Education Class”
  • Custom Settings
    • Will be used to store values and metrics
      • Days before the class that an instructor needs to confirm classroom
    • The Business can edit these settings without having to come back to me to edit code (always a good thing)
  • APEX / VF
    • Because I just want this to work from this point on, we’re going to programatically set Task field values through a wizard of sorts
    • Process Flow
      • User hits “Confirm Classroom” Custom Button from Education Object
      • APEX Controller will assemble the basic Task object with pre-populated data according to business rules
        • Pulling from Custom Settings
      • A Visualforce “Interstitial” page will appear confirming some limited data choices with instructions
      • Users hits “Next” on the Interstitial Page
      • APEX Controller will pull in the user’s data choices into the Task object and insert to the database
      • APEX Controller will bring the user to the newly completed Task with a return path to the Education Class (where they started)
THE GUTS:
1.  Review Custom Objects / Custom Settings
  • Custom Object:  Education Class / Education_Class__c
    • Fields
      • Id
      • Name
      • Instructor (lookup to User)
      • Classroom (lookup to Classroom__c)
      • Class Date
  • Custom Object:  Classroom / Classroom__c
    • Fields
      • Id
      • Name
      • Scheduling Contact (lookup to Contact)
      • Site Address
      • Scheduling Notes
  • Custom Setting:  (List) Custom Task Values / Custom_Task_Values__c
    • Fields
      • Checkbox:  Enable Task Fields (I always build in a shutoff valve)
      • Number:  Days Before Class
      • Text(80):  Task Subject
      • TextArea(255):  Task Body Header
    • Name
      • APEX Task
        • Enable Task Fields = true
        • Days Before Task = 2
        • Task Subject = “Confirm Classroom Availability”
        • Task Body Header = “An Education Class has been scheduled for this Classroom.  You need to verify the Classroom’s availability “
2.  Source Data

Scheduling Contact

Class

Classroom

3.  Create Interstitial Controller / Page
APEX Controller:  (word wrapped – FYI)
public class CustomTaskController {

//////////// HEADER ////////////////////
// This class handles the creation of a pre-populated Task from the Education Classes Page
// Referenced by | CustomTaskInterstitial.page
// Created on 20111022 by Andrew Boettcher
// Support Info:
// <my support email>
// <my phone number>
//////////// HEADER ////////////////////

/////////////////////
// Class Variables
/////////////////////
Id idEducationClass = null;
public Education_Class__c ecCurrent {get;set;}
public Classroom__c clCurrent {get;set;}
public Task tskNew {get;set;}
public Custom_Task_Values__c csTaskValues = Custom_Task_Values__c.getValues('APEX Task');

/////////////////////
// Constructors
/////////////////////
public CustomTaskController(ApexPages.StandardController conMain) {

// Set Variables
idEducationClass = conMain.getId();
ecCurrent = [SELECT Id, Name, Class_Date__c, Instructor__c, Classroom__c FROM Education_Class__c WHERE Id = :idEducationClass];
clCurrent = [SELECT Id, Name, Scheduling_Contact__c, Site_Address__c, Scheduling_Notes__c FROM Classroom__c WHERE Id = :ecCurrent.Classroom__c];

// Instanciate and pre-populate Task
createTaskRecord();
}

/////////////////////
// GETers
/////////////////////

// None.

/////////////////////
// Actions
/////////////////////
public void createTaskRecord() {

///////////
// Create Task Object from Business Rules
///////////

// Instanciate Object
tskNew = new Task();

// Set Initial Variables
Integer intDaysBeforeClass = Integer.valueOf(csTaskValues.Days_Before_Class__c);
Date dteActivityDate = ecCurrent.Class_Date__c.date();
String strNotes = csTaskValues.Task_Body_Header__c;

// Set Business Rules
dteActivityDate = dteActivityDate.addDays(-intDaysBeforeClass);
strNotes += ' ' + intDaysBeforeClass + ' days before the start of the class.\n\n';
strNotes += 'Special Scheduling Notes:\n';
strNotes += clCurrent.Scheduling_Notes__c;

// Pre-populate Fields
tskNew.WhoId = clCurrent.Scheduling_Contact__c; // Set Scheduling Contact
tskNew.WhatId = ecCurrent.Id; // Refer to Education Class
tskNew.Subject = csTaskValues.Task_Subject__c; // Pull CS Subject
tskNew.ActivityDate = dteActivityDate; // Pull computed date
tskNew.Description = strNotes; // Pull concatenated text
tskNew.OwnerId = ecCurrent.Instructor__c; // Set as instructor of class

}

public PageReference saveAndProceed() {

///////////
// Save Task and Redirect user to Task Page
///////////

// Save the Task
try {
insert tskNew;
} catch(DMLException e) {
tskNew.addError(e.getMessage());
return null;
}

// Send user to Task with Return URL of Education Class
PageReference pf = new PageReference('/' + tskNew.Id + '?retURL=/' + ecCurrent.Id);
pf.setRedirect(true);
return pf;

}

}
Visualforce Page: (word wrapped – FYI)
<apex:page id="pgTaskCreate" standardController="Education_Class__c" extensions="CustomTaskController" title="Verify Task Information" tabStyle="Education_Class__c">
<apex:form id="frmTask">

<apex:sectionHeader title="Create Classroom Reservation Task" />
<apex:pageBlock >

<font color="red"><apex:messages ></apex:messages></font>

<apex:pageBlockButtons >
<apex:commandButton id="cmdCreateTask" value="Create Task" action="{!saveAndProceed}" />
<apex:commandButton id="cmdCancel" value="Cancel" action="{!cancel}" />
</apex:pageBlockButtons>

<apex:pageBlockSection collapsible="true" title="Education Class and Classroom Information">

<apex:outputField id="ofClassName" value="{!ecCurrent.Name}" />
<apex:outputField id="ofInstructor" value="{!ecCurrent.Instructor__c}" />
<apex:outputField id="ofClassDate" value="{!ecCurrent.Class_Date__c}" />
<apex:outputField id="ofSchedulingContact" value="{!clCurrent.Scheduling_Contact__c}" />

</apex:pageBlockSection>

<apex:pageBlockSection collapsible="true" title="Classroom Reservation Task Information">

<apex:inputField id="ifOwnerId" value="{!tskNew.OwnerId}" />
<apex:inputField id="ifWhoId" value="{!tskNew.WhoId}" />
<apex:inputField id="ifActivityDate" value="{!tskNew.ActivityDate}" />

</apex:pageBlockSection>
</apex:pageBlock>

</apex:form>

</apex:page>
4.  Create Custom Button and give it a whirl!

Class with Custom Button

New VF Create Task Screen

New VF Create Task Screen – Field Error

BOOM! Task.

That’s all there really is to it.  Now of course you need to write a Test Class and all that jazz to deploy it, but it’s a quick and elegant solution to keep clutter out of your user’s faces with minimal development effort.  (I wrote this whole thing in about an hour)

(I could have really written in some more error handling in the Controller, but I just whipped this up as an example.  I’m not going to do ALL of your work for you.  *smile*)

Questions?  Comments?  Hit me up in the comments below.