96

Sometimes questions are posted here that would best be answered by helping the questioner learn how to do their own debugging. (Remember that proverb?) I'd like to have something to link to on this site for that purpose.

So please provide a step by step recipe for how to output basic debug information from Apex code in triggers or controllers for inexperienced Salesforce developers.

Also see How do I start to debug my own Visualforce/JavaScript?.

PS

If/when this Force.com IDE Debugger. New feature? appears Apex may/should become as easy to debug as other languages.

PPS Looks like Winter '16 has the interactive debugger for Apex though it is something that has to be opted in to and paid for (and has yet to be widely tried). See Apex debugging in Winter '16 - how well does it work?

  • 5
    This may not be a step-by-step recipe, but the system.debug() method is your best friend. Literally pepper your code with these calls, since when you test your code in a sandbox and have debug logging on (logging level = debug) every message is written into the debug log. I use it to see variable values before and after actions. – akarnid May 21 '14 at 10:44
  • 1
    Let's say you have written a trigger and want to know specific values in the code to find out why it isn't working, and you have set a few debug statements in the trigger code. 1. Save the code. 2. Go to Monitor -> Logs -> Debug Logs 3. Click the New button in Monitored Users. Find your user and select it and save. 4. Trigger the trigger somehow (if it fires on a field update, create a test record and update the field and click Save). 5. Go to Monitor -> Logs -> Debug Logs again. Now you will see a couple of new logs for your user. You can click 'View' and you should see your debug info – akarnid May 21 '14 at 11:49
  • 1
    @akarnid that information would be more useful (and readable) as an answer rather than a comment. – BarCotter May 21 '14 at 12:29
  • 1
    When using system.debug() to output values from your code, add a prefix that doesn't occur elsewhere in your output. That way, you can filter for just the output of your own system.debug() calls (eg. "MyNewCodeMar2014-" as prefix gives "MyNewCode2014-#of cases: 23" as output) – Jagular May 21 '14 at 14:50
  • 1
    The proverb if anybody doesn't know it: 'Give a man a fire and he's warm for a day, but set fire to him and he's warm for the rest of his life.' - Terry Pratchett. – Jim W May 28 '16 at 19:52

10 Answers 10

109

Here is how I debug my issues. In most cases I would only make it to step 2 before I solve my problem.

Step 1: Explain it to your Rubber Duck

I try explain what my code is doing to my rubber duck. A lot of the time I figure out the problem when I'm explaining the code to someone else. (If exceptions are involved, take a look at your code at the line numbers reported and consider what could have generated the exception.)

Step 2: System Debugs

Debug log recording in Setup is turned on for your User via: Setup > Monitoring > Debug logs. See here for more information.

I would place temporary debug statements such as System.Debug('>>>> the value of x is ' + x); within my code to make sure that the code is executing the way I think its working. Individual SObjects, Maps of SObjects and Lists of SObjects can all be appended and that shows you all populated SObject fields.

The >>>> is a unique string that usually doesn't appear anywhere else in the log files. This allows me to quickly find my debug output. (Logs are truncated after 2M bytes of output - there are work-arounds for this.)

Step 3: Use the Developer Console

The Developer Console is a great tool for debugging. You do the following things (and more) with the developer console

  • View Logs. This is another way of viewing debug output.
  • Execute SOQL. This can be used to verify that the SOQL in your code is returning the correct information
  • Execute Anonymous. Apex code can be run directly from the dev console
  • Checkpoints can be added in the code (maximum of 5 per class), which will allow you to stop the code executing and to see variable information.

See Josh Kaplans YouTube video for more info on the dev console

Step 4: Create a Unit Test

A unit test is a great way to figure out what is going on with a piece of code. It allows you to:

  • Execute your code in an environment with no other data
  • Create test data that you can use over and over again.
  • Use asserts to check your code e.g. System.assert(contacts.size() > 0); or System.assertEquals(expectedX, actualX);

Step 5: Take a break

I find myself getting frustrated when I have been looking at the same problem for a long period of time. This does not help solve the problem, it can actually make it harder to clearly see what is going on in the code. Take a break for a while and you may find that when you look at the problem again it makes more sense.

Step 6: Ask for help

If you have done all the steps above and reached this point then you most likely need help. This is where a colleague or stack exchange come in. Make sure when asking a question that you clearly state your problem, provide enough information to make it understandable to others and if you are providing a code sample make sure that it is formatted and easy to read.

  • 20
    Nice. +1 for rubber duck; she never gets enough attention. If you want nothing but debug logs, turn all your log settings to the "error" level, then use System.debug(LoggingLevel.ERROR, someValue). You'll get small logs (mere Kb) with just the info you requested. – sfdcfox May 21 '14 at 15:21
  • 13
    I try to avoid the use of debug statements like the one mentioned using a unique string like >>> unless I plan to remove them when I am done troubleshooting, since they're not helpful to anyone else. Instead, I attempt to create useful, verbose debug statements that can live in the code forever and will probably be beneficial to other devs/admins troubleshooting at a later time. For instance: system.debug('Found a matching record using the postal code prefix [' + aWrapper.postalCodePrefix + '] but assignee UserId [' + postalCodeOwnerAssigment.Assignee__c + '] is an inactive User.'); – Mark Pond May 21 '14 at 18:34
  • 3
    I agree Mark. I have changed my answer to say that it is a temporary debug statement – BarCotter May 22 '14 at 10:00
  • 1
    I usually print apex:pageMessages in Visualforce page or use Trigger.addError in triggers for debugging, they are faster than looking at debug logs sometimes. – Raul Feb 20 '17 at 19:05
  • people worry about me talking to myself especially when working - actually i talk to rubber duck which can be my other self. – unidha Oct 31 '18 at 7:59
11

I use following techniques:

1) Developer console : Go to [User Name] -> Developer Console. It will open a popup for you where you can run your code, run SOQL and monitor debug logs of executed code.

2) Debug Logs: Sometimes jobs are executed in the background and so monitoring from the developer console becomes difficult. In such cases, we can use Setup -> Monitor -> Logs -> Debug Logs to monitor logs. Also, you can monitor at the user/class/trigger level and filter by log level to get to reduce noise from log.

3) Send email you can send email from apex code to notify the status of log output when log is truncated due to huge size.

4) Log object(Custom object) you can create a custom object to insert the log status as a new record based on custom setting. This is very useful if you have a managed package and customer face any intermediate issue. In such cases you can set the custom setting for that customer and check the records log object to see what was causing the issue.

5) anonymous block you can use anonymous block to debug/execute specific code and verify if its working fine.

Here are some helpful reference links :

http://help.salesforce.com/apex/HTViewHelpDoc?id=code_system_log.htm

https://help.salesforce.com/HTViewHelpDoc?id=code_debug_log.htm&language=en_US

8

I've added an Apex debugger to Illuminated Cloud that allows you to step through code, see variable values, etc. It uses information from debug logs and checkpoints to "replay" the executed process, and it's tightly integrated into other IDE features such as unit test execution, anonymous Apex, and the integrated log viewer.

For small-to-medium processes, the experience is very similar to an interactive debugger. For larger processes that would exceed the maximum debug log size, it still allows you to stop at registered checkpoints and review heap dump and action script results in the IDE.

You can find out more here:

http://www.illuminatedcloud.com/home/offlinedebugger

And here's a short video showing it in use:

https://youtu.be/NVxUq-CUN8A

  • So not using the hard to get and expensive Apex debugger APIs? Nice. I'll pass this on to my colleague who is our Illuminated Cloud advocate. – Keith C Apr 22 '16 at 21:04
  • 2
    That's correct. It doesn't use anything you don't already have, even in a completely free developer edition org. Obviously it's going to be subject to the limitations of the features that it's using, in particular the maximum debug log size of 2MB and the formatting of some of the variable values (though checkpoints help with both of these), but I'm quite pleased with how it's turned out. Hopefully others will find it useful as well, especially given the limited options we've all had available to us! – Scott Wells Apr 22 '16 at 21:13
6

Make an APEX class that can run unit tests and print output:

  1. Login to salesforce (I'm on development side).
  2. Choose Setup and expand the Develop category.
  3. Choose "Apex Classes".
  4. Choose "New" button to make a new class. (You may need to add permissions).
  5. Paste in this code:

    @isTest
    public with sharing class Test_Foobars {
      static testMethod void testFoobars(){
        System.debug(Logginglevel.INFO, 'You forgot to refromulate the subspace responders!');
        System.assertEquals('uranium235', 'uranium238');
      }
    }
    
  6. Save it as "Test_Foobars"

  7. You have to turn on Debugging for your user. Go back to salesforce and click "Setup".
  8. Expand the "Logs" category.
  9. Click the "Debug Logs" item.
  10. Under "Monitored Users", click "New".
  11. Type in your first name, click the magnifying glass to select yourself from the list.
  12. choose Save.
  13. Go to the Apex class you created earlier. Setup->Develop->Apex classes->Test_Foobars
  14. Under the "Apex Class Detail" category choose "Run Test". Wait for it to be done.
  15. Go back to Setup->Logs->Debug Logs Look under the "Debug Logs" header.
  16. Sort by time run descending, you should see the output of your test.
  17. Next to your name, click "View".
  18. Under the "log" section you see this:

    APEX_CODE,DEBUG;APEX_PROFILING,INFO;CALLOUT,INFO;DB,INFO;SYSTEM,DEBUG;VALIDATION,INFO;VISUALFORCE,INFO;WORKFLOW,INFO
        10:11:27.565 (565036214)|EXECUTION_STARTED
        10:11:27.565 (565106209)|CODE_UNIT_STARTED|[EXTERNAL]|01pg00000001qxv|Test_Foobars.testFoobars
        10:11:27.565 (565925400)|METHOD_ENTRY|[2]|01pg00000001qxv|Test_Foobars.Test_Foobars()
        10:11:27.567 (567067604)|SYSTEM_MODE_ENTER|false
        10:11:27.567 (567080797)|SYSTEM_MODE_EXIT|false
        10:11:27.567 (567091913)|METHOD_EXIT|[2]|Test_Foobars
        10:11:27.567 (567139033)|SYSTEM_MODE_ENTER|false
        10:11:27.567 (567268931)|SYSTEM_METHOD_ENTRY|[4]|System.debug(APEX_OBJECT, ANY)
    
        10:11:27.567 (567307215)|USER_DEBUG|[4]|INFO|You forgot to refromulate the subspace responders!
    
        10:11:27.567 (567316940)|SYSTEM_METHOD_EXIT|[4]|System.debug(APEX_OBJECT, ANY)
        10:11:27.567 (567334906)|SYSTEM_METHOD_ENTRY|[5]|System.assertEquals(ANY, ANY)
        10:11:27.567 (567412068)|EXCEPTION_THROWN|[5]|System.AssertException: Assertion Failed: Expected: uranium235, Actual: uranium238
        10:11:27.567 (567491823)|SYSTEM_METHOD_EXIT|[5]|System.assertEquals(ANY, ANY)
        10:11:27.567 (567507919)|SYSTEM_MODE_EXIT|false
        10:11:27.567 (567565312)|FATAL_ERROR|System.AssertException: Assertion Failed: Expected: uranium235, Actual: uranium238
    
        Class.Test_Foobars.testFoobars: line 5, column 1
        10:11:27.567 (567580474)|FATAL_ERROR|System.AssertException: Assertion Failed: Expected: uranium235, Actual: uranium238
    
        Class.Test_Foobars.testFoobars: line 5, column 1
        10:11:27.227 (567602387)|CUMULATIVE_LIMIT_USAGE
        10:11:27.227|LIMIT_USAGE_FOR_NS|(default)|
          Number of SOQL queries: 0 out of 100
          Number of query rows: 0 out of 50000
          Number of SOSL queries: 0 out of 20
          Number of DML statements: 0 out of 150
          Number of DML rows: 0 out of 10000
          Maximum CPU time: 0 out of 10000
          Maximum heap size: 0 out of 6000000
          Number of callouts: 0 out of 100
          Number of Email Invocations: 0 out of 10
          Number of future calls: 0 out of 50
          Number of queueable jobs added to the queue: 0 out of 50
          Number of Mobile Apex push calls: 0 out of 10
    
        10:11:27.227|CUMULATIVE_LIMIT_USAGE_END
    
        10:11:27.567 (567632141)|CODE_UNIT_FINISHED|Test_Foobars.testFoobars
        10:11:27.570 (570273184)|EXECUTION_FINISHED
    
  19. There you can see the debug output (buried in it) and the results of the unit test.

It's hard to use, hard to find and configure, hard to turn on, but once it's working it's not so bad.

Now you can salesforce good. Dude, do you even apex? Y U NO APEX??

5

The mechanics of how to get debugging information have been covered effectively in the other answers. This is more of a 'how-to fish guide' to use your metaphor.

  1. You start with a symptom of the problem which could be anything: incorrect data in UI, exceptions, error log. I call this the 'tail of the snake'.
  2. Now you have to pull on the snake's tail to follow the chain of causation, in several iterations until you get to the head of the snake -- the root of the problem. Here is how you pull on the tail:
    • Write a test that consistently reproduces the problem. This will help you iterate and also verify that you've fixed the problem.
    • Find the line of code that printed the error, threw the exception or wrote the bad data to the UI.
    • In the method you've identified, add checkpoints and trace (System.debug) statements to determine how you got to that line of code. If you are in an exception handler, which line of code in the try block threw the exception? If it's not an exception, you will need to trace the data that caused your code hit the branch of code that is symptomatic of the problem -- the data may be a method parameter or DB data.
    • Execute the test.
    • Inspect the logs. If you can't figure out the cause of the bug, you need to trace the problem higher up the chain of causation following a 'bad value'. You will need to add more checkpoint and trace statements and repeat this cycle until you get to the exact line of offending code.
    • Once you think you fixed the code, run your test again and see if it passes.

Like with fishing, the more you practice the better you will get over time.

4

You could try using the Salesforce Streaming Debugger application to get log the output that will aid in debugging. This essentially makes callouts to a Heroku app for logging.

  • I have always found, Salesforce debugger doing the Job effortlessly. Just copy RestLoggerClass into Apex and call RestLogger.debug('name', data); – Kiba Sep 8 '15 at 19:38
  • Keeping in mind that you cannot do any DML prior to the debugging which limits the implementation dramatically – Eric Sep 8 '15 at 19:54
3

Some time ago I created the Salesforce logging tool which displays debug logs in more friendly way in a 'realtime' manner. It also let one to refresh the log limit which I found a little bit inconvenient on Salesforce page.

It is very early release which was created for personal usage, but feel free to use it and contribute.

  • May i suggest you to add some documentation or simple write up on how to use it? – AtulRajguru9 Mar 21 '16 at 4:51
3

Just in case there weren't already enough "log replay debuggers" out there, I wrote another for vscode (dependant on mavensmate).

It's still pretty much in alpha, but is stable enough that you can set breakpoints and step through your code with decent variable inspection.

Best of all, it's free and open source so you can extend it and help me fix bugs!

3

There is a new replacement for Apex Debugger coming this Summer in beta called Apex Replay debugger that supports a variety of consoles, not just Eclipse like the current version. Particularly, it now better supports SFDX and VS Code.

You can see a demo of it starting at around 32:00 in the following video from TrailheaDX: https://developer.salesforce.com/trailheadx/sessions?q=a2q3A000001py7cQAA#march-28

2

Just to add - if you're looking at the Apex debugger tying into VS Code (either new one or existing), you won't be able to do this with a trial dev hub.

Just since you mentioned it in your PPS.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.