Home > Apex > If Computers Could Barf – Salesforce Debug Log

If Computers Could Barf – Salesforce Debug Log

March 1st, 2010

This story starts some time ago. I have been complaining about the system/debug log in salesforce.com ever since they released what I would consider version 1.1. You can see my post here, Please fix the Debug Log!, pleading for salesforce to fix the debug log. This was back in July of 2008! From what I can tell there has only been two noticeable changes with this debug log. I will refer to them as version 1.1 which was implemented around the time of the message board post above and the the most recent Spring ’10 incarnation which I will refer to as version 2.0.

I still remember the good old days of the debug log, version 1.0 . Everything was so peachy! Apex was brand new. The debug log output was concise and easy to use. Times where good. Version 1.0 was the best! Sigh…… (this is a sigh of fond happy memories). It’s pretty sad version 1.0 is what I consider to be the best, usually software is supposed to get better with subsequent releases right? Right?!?!?

The clouds became dark (pun intended ;-) ) with version 1.1. Now the debug log could log workflow and validation rules! Great! Now my debug logs are incredibly long and full of junk that I rarely, and 99% of the time, never care about when debugging Apex. In orgs that have a lot of workflow rules this makes it terribly painful to do bulk debugging. But Jason, simply set the Log Category to Apex Code and it will only show Apex related output.

logcategory

BWAHAHHAAHHAHA, oh man, that’s a good one. Up until version 2.0 this had never worked right. It doesn’t matter what you set the Log Category to as it never outputs what you want it to.

I remember attending the “Meet the Developers” session at Dreamforce 09 and hearing the salesforce team say that a new and improved debug log was coming. The room literally roared with applause. I was one of those clapping with excitement. When I finally was able to access the new debug log I was giddy with excitement. Will this be everything I have hoped and dreamed for? Will it save me tons of time? Will it make me a hot breakfast every morning? To my amazement and surprise it has fallen short on nearly all of my expectations.

You can’t re-size the input box. This was an incredibly useful feature. Why would a useful feature be removed? It makes no sense. Yes, there are work arounds using browser plugins such as Gresemonkey and Stylish but people don’t want workarounds. They want it to just work.

I may be on a pretty good rant but I have no right to complain if I make no attempt to help improve the tool. I decided to take a stab and building this re-size functionality and it literally took me less than 10 minutes to get a working prototype using jQueryUI. You can check it out here. It is a little rough around the edges but if I can build a working demo this quick there is absolutely no reason salesforce shouldn’t be able to incorporate this functionality.

The output is also hideous. Perhaps this is the way Java code typically outputs debug logs. I don’t have enough experience to know. What I do know is this new version makes my life less happy. From a usability perspective the old version was much easier to quickly scan and find what you were looking for. Let’s compare.

Below I will show the debug outputs for a very simple piece of code. Here is the code:

for(Opportunity opp : [select Id, Name, Amount from Opportunity]){
	system.debug(opp);
}

First let’s look at version 1.1, pre Spring 10.

20100210185937.897:AnonymousBlock: line 1, column 1: SelectLoop:LIST:SOBJECT:Opportunity
20100210185937.897:AnonymousBlock: line 1, column 23: SOQL query with 6 rows finished in 5 ms
20100210185937.897:AnonymousBlock: line 2, column 1: Opportunity:{Name=Territory Test, Amount=152989.18, Id=00660000008gWE1AAM}
20100210185937.897:AnonymousBlock: line 2, column 1: Opportunity:{Name=Pipeline Date Test, Amount=5000.00, Id=00660000008gpbDAAQ}
20100210185937.897:AnonymousBlock: line 2, column 1: Opportunity:{Name=Product Alert Test 123, Amount=555000.00, Id=00660000008gCQ7AAM}
20100210185937.897:AnonymousBlock: line 2, column 1: Opportunity:{Name=Giant Product List, Amount=0.00, Id=00660000009lsB7AAI}
20100210185937.897:AnonymousBlock: line 2, column 1: Opportunity:{Name=Silver Error, Amount=150000.00, Id=00660000009lx17AAA}
20100210185937.897:AnonymousBlock: line 2, column 1: Opportunity:{Name=Visual Force, Amount=0.00, Id=0066000000AFuB8AAL}
20100210185937.897:AnonymousBlock: line 1, column 1:     Number of iterations: 1
 
Cumulative resource usage:
 
Resource usage for namespace: (default)
Number of SOQL queries: 1 out of 100
Number of query rows: 6 out of 10000
Number of SOSL queries: 0 out of 20
Number of DML statements: 0 out of 100
Number of DML rows: 0 out of 10000
Number of script statements: 6 out of 200000
Maximum heap size: 0 out of 2000000
Number of callouts: 0 out of 10
Number of Email Invocations: 0 out of 10
Number of fields describes: 0 out of 10
Number of record type describes: 0 out of 10
Number of child relationships describes: 0 out of 10
Number of picklist describes: 0 out of 10
Number of future calls: 0 out of 10
Number of find similar calls: 0 out of 10
Number of System.runAs() invocations: 0 out of 20
 
Total email recipients queued to be sent : 0
Cumulative profiling information:
 
1 most expensive SOQL operations:
AnonymousBlock: line 1, column 23: [select Id, Name, Amount from Opportunity]: executed 1 time in 5 ms
 
No profiling information for SOSL operations.
 
No profiling information for DML operations.
 
No profiling information for method invocations.

Why do I like this? It is incredibly easy to identify line and column numbers. When debugging I am usually focused on a specific area. In any browser I can hit CTRL-F, enter “line 142″, and be taken straight to the area I am debugging. The output is very clean and concise with no unwanted garbage. It simply has my debug statements. It also provides a nice clean summary of limits and the most expensive methods, SOQL, SOSL, and DML statements. This is great information to know when optimizing code. For me this is perfect. The only issue I had with version 1.1 was that if my code had any DML statements it would output all of the work flow and validation criteria because the filters did not work as mentioned above.

Now lets take a look at version 2.0 released with Spring 10.

Below are the filter settings I used for this:

filters
11:03:30.381|EXECUTION_STARTED
11:03:30.381|CODE_UNIT_STARTED|[EXTERNAL]System Log Window
11:03:30.393|METHOD_ENTRY|[2,2]|system.debug(SOBJECT:Opportunity)
11:03:30.393|USER_DEBUG|[2,2]|DEBUG|Opportunity:{Name=Edge SLA, Amount=60000.00, Id=006A0000002YZZ9IAO}
11:03:30.393|METHOD_EXIT|[2,2]|debug(ANY)
11:03:30.393|METHOD_ENTRY|[2,2]|system.debug(SOBJECT:Opportunity)
11:03:30.393|USER_DEBUG|[2,2]|DEBUG|Opportunity:{Name=Grand Hotels Kitchen Generator, Amount=15000.00, Id=006A0000002YZZAIA4}
11:03:30.393|METHOD_EXIT|[2,2]|debug(ANY)
11:03:30.394|METHOD_ENTRY|[2,2]|system.debug(SOBJECT:Opportunity)
11:03:30.394|USER_DEBUG|[2,2]|DEBUG|Opportunity:{Name=Grand Hotels SLA, Amount=90000.00, Id=006A0000002YZZBIA4}
11:03:30.394|METHOD_EXIT|[2,2]|debug(ANY)
11:03:30.394|METHOD_ENTRY|[2,2]|system.debug(SOBJECT:Opportunity)
11:03:30.394|USER_DEBUG|[2,2]|DEBUG|Opportunity:{Name=Express Logistics Portable Truck Generators, Amount=80000.00, Id=006A0000002YZZCIA4}
11:03:30.394|METHOD_EXIT|[2,2]|debug(ANY)
11:03:30.394|METHOD_ENTRY|[2,2]|system.debug(SOBJECT:Opportunity)
11:03:30.394|USER_DEBUG|[2,2]|DEBUG|Opportunity:{Name=Express Logistics SLA, Amount=120000.00, Id=006A0000002YZZDIA4}
11:03:30.394|METHOD_EXIT|[2,2]|debug(ANY)
11:03:30.394|METHOD_ENTRY|[2,2]|system.debug(SOBJECT:Opportunity)
11:03:30.394|USER_DEBUG|[2,2]|DEBUG|Opportunity:{Name=Express Logistics Standby Generator, Amount=220000.00, Id=006A0000002YZZEIA4}
11:03:30.394|METHOD_EXIT|[2,2]|debug(ANY)
11:03:30.394|CODE_UNIT_FINISHED
11:03:30.394|EXECUTION_FINISHED

And this brings us back to the title of this post. If computers could barf I’m pretty sure it would look like the output above. Basically every pro in the previous example has now become a con. The noisy output makes it difficult to isolate line numbers and specific areas. This small example is not so bad but imagine a debug log with hundreds if not thousands of lines. What was done in 9 output lines now takes 22 lines!

What is the point of this line: “11:03:30.394|METHOD_EXIT|[2,2]|debug(ANY)” when the line that is actually a debug statement says “|DEBUG|”. I’d really like to know as it looks pretty pointless.

This line is also unnecessary, “11:03:30.394|METHOD_ENTRY|[2,2]|system.debug(SOBJECT:Opportunity)”. Yes, thank you for letting me know I am debugging an Opportunity. I was the one who wrote this debug statement so I know what I am debugging. The next line that says, “Opportunity:{Name=Express Logistics” also lets me know I am debugging an Opportunity. I see how this could be helpful for someone looking at new or unfamiliar code but for me it does nothing more than get in the way.

You will also notice the limit and performance metrics are gone. The only way to get these metrics back is to enable Database logging but then the output starts to includes items that I may not want, again making the output even longer.

Not all is bad with version 2.0. The ability to save the debug logs is useful and the logging criteria actually works.

What I want to be able to do is get a very clean and easy to read output that only displays system.debug() statements with limit and performance metrics. Nearly 2.5 years after I started developing Apex I still don’t have this and it makes me sad.

Salesforce.com usually gets it right but with this particular feature I feel like they keep striking out. It feels like this tool received little to no customer usability testing. The CRM piece of salesforce is always having usability testing done but I have never been approached to give feedback on the developer tools. I would encourage the salesforce.com dev group to reach out and do a little usability testing. It doesn’t need to be super formal usability testing. Quick online group meetings with force.com developers would suffice. There are plenty of good force.com developers out here that are more than willing to give constructive feedback on features like this.

The issues I have expressed concern about may eventually be fixed but we are at least four months away from the next release and based on past changes (or lack there of) to this tool I can’t be optimistic that improvements will be made quickly. This tool is was close to being perfect and I think it could have hit a home run if it incorporated some user feedback before it was rolled out.

</end rant>

Categories: Apex
  1. March 1st, 2010 at 10:54 | #1

    Thank you for concisely elucidating what I had only perceived in simian confusion and expressed in dockyard slang and hand-gestures.

  2. March 1st, 2010 at 12:49 | #2

    Agree with most of what you are saying. There is no question that you can now get better and more information than you could previously. When an Apex web service is invoked that calls a bunch of functions, that may result in triggers etc, it’s helpful to have the method start and end entries. For simple code it’s a bit much, but I have been doing this for a while myself, with some fairly complex code and been frustrated by the lack of information that was previously provided. The new one helps.

    It looks crappy, the lack of resizing is poor design. I will frequently write 10′s of lines of apex in the execute code area and the 3 or 4 lines that are shown now don’t make my boat float. I even wrote a GM script to reformat the output.

    Which bounces me back to a plus with the new that you touched on, the ability to export the log. It is also pipe delimeted to make formatting easier. Overall, I agree, seems like an after thought (the usability). Having said, I have seen the future my friend. This log is not long for this world and the replacement for it truly a thing of beauty. Hang in there, just a couple more months and we will see a GIGANTIC improvement. (That’s all I can say, safe harbor and all).

  3. March 1st, 2010 at 12:57 | #3

    @Dave Thanks for the comment and I appreciated the feedback. Happy to hear improvements are on the way but I hope some of my concerns are addressed in the next release. I do see how the entry and exit lines could be useful but for me they get in the way more often than they help.

  4. March 1st, 2010 at 13:14 | #4

    Couldn’t agree with you more. The new debug logs drive me nuts. Plus, the filtering doesn’t work in the current IDE. I really hope it works when they eventually release the Spring ’10 version. I’ve even had cases where running the tests in the IDE don’t properly respect the filter settings.

    For handle input box resizing in System Log, I installed the “Text Area Resizer and Mover” extension for Firefox. It’s a good interim fix.

  5. March 1st, 2010 at 13:29 | #5

    My ‘hack’ for getting around log noise in Eclipse is to:

    1) Use a unique prefix ,like system.debug(“foo:” + actual value).
    2) Cut-n-paste the log output into Notepad++
    3) CTRL-F find the prefix

    Yes, it’s a few extra steps, but relatively faster than hunt-and-find. Hoping the Spring ’10 filters will force a change in my debugging habits. I really need to use and trust the browser System log more.

    I would agree with Dave that the latest approach is the lesser of 2 evils. It would be *way* more frustrating to *not* have transparency into the full execution lifecycle, including triggers. If you’ve ever had triggers magically change data behind the scenes, you’d agree that’s a “bang head on the desk” situation.

  6. Manu
    March 1st, 2010 at 13:35 | #6

    What great timing for the post – I had the (mis)fortune of trying to debug code while deploying from a Win’10 Sandbox to a Spring’10 production org today that had a multitude of custom apps already on! The horror of the new logger struck me when it didn’t point out which row of which function of which class was failing! if it wouldn’t have been my own code, I’m not sure how much time it’d take to debug and fix it! Luckily, that wasn’t so but it sure’s going to take some time getting used to the new logging for sure!

    As usual, great post, Jason!

  7. Rich Unger
    March 1st, 2010 at 15:04 | #7

    The point of the new logging format is to make it more easily parseable. The METHOD_ENTRY lines allow such a parser to trace where it is in the call stack.

    What you see in this release is the first step on a longer road towards making the development experience with apex more enjoyable. There was a lot that had to be done on the back end before we could really do what we wanted with the interface.

    Believe me, I know how rough this feature feels right now. Please stay tuned!

  8. March 1st, 2010 at 15:20 | #8

    @Rich

    Being easy to parse is nice…. but since I am human, not a computer, I would say being easy to read takes priority for me.

    I’m guessing (hoping) now that it’s easy to parse you will have some UI improvements that will make it easy to read.

    I’m glad to hear you can see, in it’s current state, it is rough to use and improvements are on the way.

  9. Rich Unger
    March 3rd, 2010 at 16:27 | #9

    BTW, one workaround you can use if you just want to see the System.debug() output is to use the logging levels, e.g.: System.debug(LoggingLevel.INFO, ‘foo’)
    and set your filter for the APEX_CODE category to INFO. The METHOD events get logged in the DEBUG level, which is one below INFO.

  10. Mike Eaton
    March 5th, 2010 at 10:27 | #10

    Agree with you 100%. I feel like we’ve taken a giant step backwards. Hopefully we’ve hit the bottom of the barrel and can only go up from here. Keep up the good work!

  11. March 9th, 2010 at 04:46 | #11

    @Rich Unger
    Rich, I can understand this is laying the foundations for things to come, and I get an idea of what’s coming down the line… but in the here and now, things appear to have gotten more difficult.

    I’m persevering as I don’t want to write it off just because it’s different; similarly, I’m wary of making myself look an idiot because I’ve yet to grok how the feature actually works. But as far as I can tell, names of custom built methods no longer appear in the log output, which is a massive thorn in my side. I’m trying to investigate something in a production environment, updating code and deploying just for the sake of some debug statements is not exactly ideal for me…

    And as for the “makes parsing easier” – are there any tools out there at the moment that can help with this with output from Spring 10?

    Apologies for shooting the messenger, and I realise I’m partly to blame as I didn’t try it earlier and offer my feedback!

  12. March 9th, 2010 at 05:01 | #12

    @Gary B
    OK, I take part of that back – it seems (some) method names *are* in the log, apologies!

  13. March 9th, 2010 at 11:12 | #13

    The big issue for me is that I can’t get the output of System.debug() statements without also getting METHOD_ENTRY/EXIT spew (as both are in the “Apex Code:DEBUG” level).

    I think System.debug() statements should be placed into a separate Log Level than METHOD_ENTRY/EXIT. Perhaps METHOD_ENTRY/EXIT should be moved into the “Fine” log level.

    Note the Log Level-vs-Events issue is confused, because there isn’t an Event for System.debug() statements – they show up at DEBUG, but the System Log’s “Events” list only adds METHOD_ENTRY/EXIT when you go from “INFO” to “DEBUG”.

    Also, it would be useful to break METHOD_ENTRY/EXIT into USER_METHOD_ENTRY/EXIT and SYSTEM_METHOD_ENTRY/EXIT. The first only traces non-System methods; the second traces system methods. They should be placed in “FINE” and “FINER” levels, respectively.

  14. March 17th, 2010 at 08:21 | #14

    @Rich Unger
    I tried the trick, system.debug(LoggingLevel.Info,’foo’); and this is what I get, all I care about is line 5.

    15.0 APEX_CODE,INFO
    9:19:8.804|EXECUTION_STARTED
    9:19:8.804|CODE_UNIT_STARTED|[EXTERNAL]VF-Outer
    9:19:8.804|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:8.860|USER_DEBUG|[195,11]|INFO|null
    9:19:8.860|CODE_UNIT_FINISHED
    9:19:8.860|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:8.869|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:8.870|CODE_UNIT_FINISHED
    9:19:8.870|CODE_UNIT_FINISHED
    9:19:8.872|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:8.872|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:8.872|CODE_UNIT_FINISHED
    9:19:8.872|CODE_UNIT_FINISHED
    9:19:8.873|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:8.873|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:8.873|CODE_UNIT_FINISHED
    9:19:8.873|CODE_UNIT_FINISHED
    9:19:8.966|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:8.967|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:8.967|CODE_UNIT_FINISHED
    9:19:8.967|CODE_UNIT_FINISHED
    9:19:8.969|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:8.969|CODE_UNIT_STARTED|[EXTERNAL]createContact
    9:19:8.969|CODE_UNIT_FINISHED
    9:19:8.969|CODE_UNIT_FINISHED
    9:19:8.972|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:8.972|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:9.84|CODE_UNIT_FINISHED
    9:19:9.84|CODE_UNIT_FINISHED
    9:19:9.88|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:9.88|CODE_UNIT_STARTED|[EXTERNAL]territoryID
    9:19:9.88|CODE_UNIT_FINISHED
    9:19:9.88|CODE_UNIT_FINISHED
    9:19:9.98|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:9.98|CODE_UNIT_STARTED|[EXTERNAL]AE
    9:19:9.98|CODE_UNIT_FINISHED
    9:19:9.98|CODE_UNIT_FINISHED
    9:19:9.102|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:9.102|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:9.103|CODE_UNIT_FINISHED
    9:19:9.103|CODE_UNIT_FINISHED
    9:19:9.103|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:9.103|CODE_UNIT_STARTED|[EXTERNAL]ISR
    9:19:9.103|CODE_UNIT_FINISHED
    9:19:9.103|CODE_UNIT_FINISHED
    9:19:9.106|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:9.106|CODE_UNIT_STARTED|[EXTERNAL]PBM
    9:19:9.106|CODE_UNIT_FINISHED
    9:19:9.106|CODE_UNIT_FINISHED
    9:19:9.109|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:9.109|CODE_UNIT_STARTED|[EXTERNAL]primaryContact
    9:19:9.109|CODE_UNIT_FINISHED
    9:19:9.109|CODE_UNIT_FINISHED
    9:19:9.111|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:9.111|CODE_UNIT_STARTED|[EXTERNAL]body
    9:19:9.111|CODE_UNIT_FINISHED
    9:19:9.111|CODE_UNIT_FINISHED
    9:19:9.112|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:9.112|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:9.112|CODE_UNIT_FINISHED
    9:19:9.112|CODE_UNIT_FINISHED
    9:19:9.115|CODE_UNIT_STARTED|[EXTERNAL]VForcePage
    9:19:9.115|CODE_UNIT_STARTED|[EXTERNAL]error
    9:19:9.115|CODE_UNIT_FINISHED
    9:19:9.115|CODE_UNIT_FINISHED
    9:19:9.158|CODE_UNIT_FINISHED
    9:19:9.158|EXECUTION_FINISHED

  15. Sebi
    April 9th, 2010 at 03:45 | #15

    They should dim the “extra lines” and make the old stuff stand out more. That way the noise is somewhat out of the way. If you need the info, you can always focus on it with a glance.

  16. David
    August 4th, 2011 at 14:36 | #16

    Fast forward to August 2011. What are your opinions on the debug log now?

  17. November 21st, 2011 at 02:16 | #17

    I’ve been using the “Debug Logs” page in the SF UI and struggling with the debug code ever since they changed the output. I can’t believe I’ve only just realised that the debug logs will also appear in the “System Log” pop-up. Am I an idiot, or is this not particularly well sign-posted in the docs?

    All of the examples I’ve seen of the system log being used showed somebody manually typing in and executing a method, etc. My debugging potentially just got a lot easier….