Exploring CFDUMP, AKA an Ode to Dump

This post is more than 2 years old.

It may be a bit silly to say that I have a favorite tag, but I'll happily admit to being somewhat infatuated with the cfdump tag. Since it's introduction (in ColdFusion 4.5 I believe, but it was available earlier in the Spectra CMS), it's probably been my number one debugging/testing/all around useful utility tag in the language for close to a decade. I thought it might be fun to talk a bit about some of the lesser known features of cfdump. In preparation for this blog entry I've already discovered a few new things myself, so hopefully this guide will be of use to folks and really prove, once and forever, that the coolest tag ever created is cfdump.

Let's begin by looking at the bar minimum required for cfdump, the var attribute. This must be a ColdFusion variable. Not the name of a variable. (Although Railo supports passing the name of a variable.)

<cfset x = [1,2,3]> <cfdump var="#x#">

Which returns:

This is probably the way most people use the tag. You can also easily dump built in scopes as well:

<cfdump var="#url#"> <cfdump var="#form#"> <cfdump var="#cgi#"> <cfdump var="#server#"> <cfdump var="#cookie#"> etc...

You can also dump the result of calling a method or UDF.

<cfscript> function thatsHowIRoll(x) { return x*2; } </cfscript>

<cfdump var="#thatsHowIRoll(42)#">

Notice I didn't have to create a temporary variable. I can call the method right there in the tag and see the result. I might find something like this useful then:

<cfdump var="#thatsHowIRoll(41)#"> <cfdump var="#thatsHowIRoll(42)#"> <cfdump var="#thatsHowIRoll(43)#">

Now let's start looking at some of the other attributes. The first is simple - label. The label attribute is used in the display of any non-simple variable. What does that mean? Whenever you dump anything that isn't a simple string, ColdFusion wraps it in some lovely tabular structures. Watch what happens when I apply a label to two variables - one complex, one simple.

<cfset hawking = [1,2,{name="Ray",age="Almost my birthday"},4]> <cfset paris = "hilton">

<cfdump var="#hawking#" label="Complex"> <cfdump var="#paris#" label="Not so complex">

Which returns:

As you can see, the label is really useful, especially if you have more than one thing you are dumping, but it will be ignored if the value is simple. You could get around that a bit:

<cfdump var="Simple: #paris#">

This will simply prepend the paris value with a string that kind of acts like a label. Using cfdump for something you know is simple is overkill, but it's an option.

Another display related attribute is expand. This dictates if the dump should be expanded (fully visible) or compressed. The default is true and normally there isn't much use in setting the value to false, but I've done that from time to time when I don't want the dump to "explode" over a page. Even if you don't use this value, you can click the header of a dump to compress or expand the display. The docs say this only works in Mozilla and Internet Explorer, but it works fine in Chrome and Safari as well. Here is an example of two dumps, one set to expand false.

<cfset hawking = [1,2,{name="Ray",age="Almost my birthday"},4]> <cfset beer = ["good","really good", "not worth drinking"]>

<cfdump var="#hawking#" expand="false" label="Foo"> <cfdump var="#beer#" label="Beer">

Which returns:

One place where I make use of this is in Adobe Groups. When an error occurs in the publishing system, and you are logged in as an admin, I dump the error with expand="false" to keep the page layout somewhat like it should be. Like the label attribute, the expand attribute is ignored for simple values.

Now let's look at probably the most important attribute - top. The top attribute allows you to restrict the amount of data returned. In a query, this number represents the number of rows to show. In a structure, it represents how deep to go. Let's look at examples of both, starting with a query.

<cfquery name="getart" datasource="cfartgallery"> select * from art </cfquery> <cfdump var="#getart#" label="Art" top=3>

Which returns:

Notice the dump actually tells you it's filtered. Very handy in case you forget. While not documented, top works in arrays as well:

<cfset a = [1,2,4,8,16,32]> <cfdump var="#a#" top=4>

Which oddly does not report the filter:

And here is a structure example. As I mentioned above, this applies to how deep you will go into the structure. It will not limit the number of keys. So consider this structure with deeper members:

<cfset s = { name = "Ray", age = 37, race = "white", religion = "it's complicated", music = "!country", genres = { literature=["sci fi","fantasy"], music=["alt","indie","classical","jazz","cajun"] } }>

<cfdump var="#s#" top=1>

Notice the result doesn't show the contents of genres keys:

The top attribute is probably most crucial with ORM entities. When you dump a CFC that is persistent, the tag will possibly generate an incredibly large amount of HTML. Consider a simple Group object. Groups have Members. So imagine one group has 50 members. Now imagine that Users have Groups. Each user has 1-5 groups. Groups have 50 or so members. Are you guessing what's going to happen? I've brought down more ColdFusion servers than ever before by dumping an ORM entity. Unfortunately, using top in a persistent CFC can make it difficult to see whats in the object. So imagine that group with 50 members. Let's just add a top=1 to keep the dump from getting too big.

<cfset g = entityLoadByPk("group", 113)> <cfdump var="#g#" top=1>

Now check out the result:

Notice that my members property, which should have a bunch of results, was limited to one. I can't easily tell the true size of the data there as the top attribute applies all the way down the dump. It would be nice (and I've blogged this before), if cfdump was more ORM-aware, and perhaps had a way to nicely handle relationships like this. In case you're wondering, top also has no impact on simple values. Don't forget though you can limit the size of a string by using a function like left:

<cfset name="Raymond Camden Smith"> <cfdump var="#left(name,10)#">

Since we're talking about limiting results, let's talk about two related attributes: show and hide. For a query, these attributes are a list of columns to either hide or show. For a structure, it's keys. In both cases, if you specify values that don't exist, ColdFusion won't mind.

<cfquery name="getart" datasource="cfartgallery"> select * from art </cfquery> <cfdump var="#getart#" label="Art" top=3 hide="artid">

Here is an example of something I've done many times - hide the primary key. If I know there are columns I don't care about and really need to focus, I'll just hide them. Ditto for using show if I just care about one column. Like top, cfdump will tell you it filtered:

<cfquery name="getart" datasource="cfartgallery"> select * from art </cfquery> <cfdump var="#getart#" label="Art" top="3" show="artid">

Which returns:

As I said, this works in structures as well, but apparently is buggy in subkeys. Consider:

<cfset s = { name = "Ray", age = 37, race = "white", religion = "it's complicated", music = "!country", genres = { literature=["sci fi","fantasy"], music=["alt","indie","classical","jazz","cajun"] } }>

<cfdump var="#s#" hide="music">

Which returns:

Notice that the top level music value was hidden, but not the subkey value. (I'll file a bug report for this in the morning.)

As long as we're still on filtering, let's cover an attribute I had completely no idea existed until tonight: keys. This works much like top, but whereas top for structures implies how deep, keys represents the number of keys to show. Consider this code:

<cfset s = { name = "Ray", age = 37, race = "white", religion = "it's complicated", music = "!country", genres = { literature=["sci fi","fantasy"], music=["alt","indie","classical","jazz","cajun"], foo="goo", zoo=[1,2] } }>

<cfdump var="#s#" keys="3">

The result of this is:

As before - note that while the filter worked on "top", it was forgotten in the substructure genres. I honestly don't know when I'd use this - but it's an option.

Ok, moving along, another option we have is format. Format can be either html (the default), or text. Using our structure from before, I simply switched the format to text and remove the keys attribute:

<cfdump var="#s#" format="text">

And consider the result:

Notice that the result is much simpler, and it's automatically formatted with PRE tags. How does a query look? Here is a text dump of my query from earlier.

It's a bit vertical for my tastes (Ben Nadel must have been here ;), but I suppose it works. So where would this be useful? The cfdump result is quite heavy in terms of HTML sent out. This version is much smaller. It could be a lot better for email. You could also save the result to the file system. How would you do that? Let's now look at another argument - output.

The output attribute can be browser (the default), console (the server console, basically a log file if you run ColdFusion as a simple service), or a random file name. The file must be a complete path. Here is an example:

<cfquery name="getart" datasource="cfartgallery"> select * from art </cfquery> <cfdump var="#getart#" label="Art" format="text" output="c:\ray.txt">

When run, nothing from the dump is output to screen. Instead, the entire thing is sent to a file. ColdFusion will append results so if you have other dumps using output and the same file, they won't overwrite each other. Also note that cfdump is smart enough to know it doesn't need the pre tags when outputting to a file. Of course, you can also output to a file with html format;

<cfdump var="#getart#" label="Art" format="html" output="c:\ray.html">

I've done this in the past for complex items I don't want to show up in the browser. I'll simply double click it and view it in my browser. A good example of this will be a dump within the model portion of a complex MVC application.

OK, still with me? Got a few more attributes to go before we're done. Now let's talk about metadata. Did you notice earlier on when I dumped the query we got some additional data? That included the cache status, SQL, and the execution time. If you don't like that, or just want to focus on the data, turn metadata off like so:

<cfdump var="#getart#" label="Art" metainfo="false" top="3">

Which returns...

Now the freaky version of this. Remember how I talked about persistent CFCs and how big they can get? Turns out the default value for metadata in persistent CFCs is false. Turning it on returns.... something odd.

What you are seeing is the result of this:

<cfdump var="#g#" top="3" metainfo="true">

The result is just plain odd. You still see much of the same data, but it considers the properties as an array of structs. It also seemingly mixes in the real database value along with the hard coded CFML. So look at the 3rd item in the array. The code behind this is:

property name="active" ormtype="boolean" dbdefault="false";

cfdump shows ormtype and dbdefault with their values, yet knew "name" was special and used the value as the key and the database value as the value. Make sense? Increasing top a bit results in some pretty complex coloring:

Freaky-Tiki. Ok, another attribute is showUDFs. This applies to any container of data. If you cfdump a UDF itself - not the call, you will always get a result

<cffunction name="helloWorld" access="public" returnType="string" output="false"> <cfargument name="name" required="true" hint="Your name"> <cfreturn "Hello, #arguments.name#"> </cffunction>

<cfdump var="#helloWorld#" showUDFs="false">

Result:

But if I switch to dumping variables, then this time the UDF will be hidden:

<cfdump var="#variables#" showUDFs="false">

Even if you turn showUDFs on (or leave it off the tag as on/true is the default), ColdFusion automatically compresses UDFs. I'm guessing here is that the thinking is that you won't normally need to see a UDF. If you wrote it, you probably already know how it's defined anyway.

And now we come to our final attribute. If you made it this far, I congratulate you. The final attribute is perfect to end on - abort. For years, folks using cfdump for testing would do something like this.

<cfdump var="#something#"> <cfabort>

If something was going wrong in their code, doing a quick dump and an abort allowed them to see the state of values and stop execution at that point. Apparently this done so much that Adobe actually made it part of the tag:

<cfdump var="#something#" abort>

Note that you do not need to actually state abort="true". Just the presence of the attribute by itself implies abort="true".

So - I hope this was helpful. I'd love to hear about any interesting dump use cases or other tricks folks may have. Any questions are also - of course - welcome.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Richard Brasier posted on 3/25/2011 at 8:16 AM

cfdump is truly awesome. When i ever do a php project I feel i need to use dBug (http://dbug.ospinto.com/ , which is a replica version for php) to compensate

Comment 2 by Jonathan posted on 3/25/2011 at 9:18 AM

I always place cfdump in the cferror template when the system mails me the cferror template

Comment 3 by Steve posted on 3/25/2011 at 9:40 AM

ha! Thanks Ray, this is great. I simply hadn't looked past what I was already using cfdump for to see what else had been added.

I notice you can also hide more than one item with a comma delimeter too. eg. <cfdump var="#s#" hide="age,music">

I'll be referring back to this a fair bit I think. Thanks again.

Comment 4 by A CF Fan posted on 3/25/2011 at 11:57 AM

Yes Steve,

"Chocolates itself is much tasty, why we look to add more to it", cfdump is GREAT

Comment 5 by Ciaran Archer posted on 3/25/2011 at 12:51 PM

Thanks Ray - I didn't know about the 'top' attribute. Today I can say I learned something new :)

Comment 6 by Neil Albrock posted on 3/25/2011 at 2:25 PM

Nice review of cfdump features Ray. I've always thought it was a fantastically useful tag but the extended options actually make it even more so!

Comment 7 by Dom posted on 3/25/2011 at 3:07 PM

Ray - you're like Steve Jobs with the "hey, and one last attribute ..." ;-) Thanks for documenting all this - there's timesavers galore here.

Comment 8 by Raymond Camden posted on 3/25/2011 at 3:14 PM

You know, I don't really take "like Steve Jobs" as a compliment. Not anymore. ;)

Comment 9 by Jim Papaleo posted on 3/25/2011 at 4:15 PM

Great info Ray. I use cfdump all the time and now I now some new tricks. (top, abort).

Comment 10 by BV posted on 3/25/2011 at 4:52 PM

Very helpful information

Comment 11 by Doug posted on 3/25/2011 at 5:05 PM

Fantastic post. I had no idea CFDUMP was so powerful. Just being able to dump as text and not html is huge. I wonder... is there a way to have the file output overwrite instead of append? In this manner I could simply attach the error.txt file to an email, rather than embedding it in the body. Almost like a drwatson log from days gone by.

Comment 12 by Raymond Camden posted on 3/25/2011 at 5:21 PM

@All: Thanks for the compliments and I'm glad to help. This was one of those blog entries where I thought, "I'll just be repeating what everyone knows", but ended up discovering new things myself. :)

@Doug: As far as I know, no. You could wrap a call that outputs to screen with cfsavecontent though and then use cffile to write it. A bit overkill, but if you made a UDF out of it, wouldn't be so bad. If you need an example of what I mean, let me know.

Comment 13 by Edward - Florida SEO posted on 3/25/2011 at 5:22 PM

I love using <cfdump var="#Application#">

Comment 14 by Raymond Camden posted on 3/25/2011 at 5:24 PM

@Edward: Want to see something interesting? Do that dump on a page that does NOT have a Application.cfc/cfm in scope. It will dump all the application scopes on the server.

Comment 15 by Matt W posted on 3/25/2011 at 5:28 PM

I think I will definitely start logging my dumps.
Is there an easy way to dump my logs?

Can't... stop... middle... school... humor...

Comment 16 by Connor Middleton posted on 3/25/2011 at 5:30 PM

Great article Ray, now I see the rainbow comment you made in twitter yesterday.

Comment 17 by Edward - Florida SEO posted on 3/25/2011 at 5:35 PM

@Ray - I Know - That's Just too Cool ...

Comment 18 by Rob Parkhill posted on 3/25/2011 at 5:47 PM

I use the output to file whenever I am trying to debug the CFCs that I have for any Flex apps. It is awesome. Add a directory watcher to the CFAdmin and anytime it dumps I can get an email. Great for diagnosing running Flex apps with a CF backend.

Comment 19 by Aaron DeRenard posted on 3/25/2011 at 6:07 PM

@Ray, Edward

I dropped in a little <cfdump var="#Application#" /> in a cfm under a site that has no Application.cfc/cfm. I got an error instead of a dump.

Variable APPLICATION is undefined.
The error occurred in C:\Sites\exttest\testapp.cfm: line 1
1 : <cfdump var="#application#" />

I'm running ACF 9.0.1.274733 Developer, and I definitely have more CF apps with application cfcs on other IIS sites, and they are currently running.

Is this something that was fixed?

Comment 20 by Raymond Camden posted on 3/25/2011 at 6:08 PM

Maybe it was plugged - or maybe I'm remembering the hack incorrectly.

Comment 21 by Raymond Camden posted on 3/25/2011 at 6:10 PM

Ok, it worked for me. I think the trick is to have an App.cfc with no name in it. So CF turns on Application scope access, but because you didn't give it a name, dumping the scope gives you ALL of them.

Comment 22 by Aaron DeRenard posted on 3/25/2011 at 6:28 PM

That did the trick! Also got some strange entries in there I'm not sure what they are, but they are not application objects best I can tell. Example, one of the struct keys was (coldfusion.jsp.taglibinfo.C:\inetpub\wwwroot\exttest\source\testsubdir.):

object of coldfusion.jsp.JRunTagLibraryInfo

Method (omitting return types)
getTag(java.lang.String)
getTagClass(javax.servlet.jsp.tagext.TagInfo)
getTags()
getURI()
isCfmDir()
lookupTLI(javax.servlet.ServletContext, java.lang.String, java.io.File)
lookupTLI(java.io.File, javax.servlet.ServletContext, java.lang.String)
lookupTLI(java.io.File, javax.servlet.ServletContext)
resolveTagLibraryURI(javax.servlet.ServletContext, java.lang.String, java.io.File)
and some other stuff in the dump that looks to be pretty much the same...

Any idea what that stuff is? I have no idea...

Comment 23 by Raymond Camden posted on 3/25/2011 at 6:33 PM

That's a Java class. Could be something your CF Admin is using.

Comment 24 by Aaron DeRenard posted on 3/25/2011 at 6:44 PM

Right, I just thought it strange, because it only appears on certain subdirectories of the various applications I've got running. At a glance, I don't see anything special about the ones listed. Oh well, not really important I suppose. I'm still surprised that dump did what it did. :-)

Thanks for the cfdump update. I never bothered looking at that tag to see if it had new features, so I appreciate it much! Have a good day!

Comment 25 by John Allen posted on 3/25/2011 at 7:02 PM

CFDUMP is my fav tag.

Comment 26 by Edward - Florida SEO posted on 3/25/2011 at 8:04 PM

<cfdump var="#THIS#"> ;-)

Comment 27 by Ryan Arneson posted on 3/25/2011 at 8:07 PM

Thanks for the tips on output and format. Since ColdFusion Builder (1) came out I use it quite a bit for watching logs TailView. I took what you said about writing the dump to a file and wrote it to a .log file in my logs directory. Then in TailView I opened the log file and I can watch the dump roll in without needing to browse to a file or to constantly close and open it. Pretty nice! This will come in handy for dumping in CFCs and other locations that I normally email myself.

Comment 28 by Henrique Feijo posted on 3/25/2011 at 10:32 PM

I still remember programming in plain ASP back in 2000 and having to do loops to see the values of a simple query. Once I learned CF in 2004 and saw the cfdump tag, that was the most amazing thing I've had ever seen so far. And it is still... kind of... I still don't know what my life would be without cfdump. I guess I would have to use Ray's custom cf_dump tag :)

Comment 29 by Sigi posted on 3/28/2011 at 12:03 PM

I like it to, thanks for the load of information!
And one more hint: I use <cfdump var='#getPageContext().getBuiltinScopes()#'> to get an overview of all variables available at the site.

Comment 30 by Rajesh Kongathi posted on 8/26/2011 at 3:20 PM

Thanks Raymond, I have learnt new things today.

Comment 31 by Pete posted on 1/31/2012 at 3:39 PM

Whilst we're on CFDUMP, something Railo does better than CF is when you CFDump a string, it gets wrapped in the nice colourful tables so it's easy to see.

When dumping strings onto the page in CF they get mixed up with the rest of the text and are harder to spot, I find anyway. I generally wrap them in <p> or follow with a <hr /> to make it easier...

It'd be nice if Zeus presented simple values in the same way it presents arrays, structs etc.

Otherwise CF ftw...

Comment 32 by Raymond Camden posted on 1/31/2012 at 5:33 PM

I agree that that would be a nice change. File an ER for it.

Comment 33 by Andrew Hewitt posted on 10/3/2013 at 1:12 PM

Thought you be interested in this, cfdump for node.js. Check it out here: https://github.com/ragamufi...

Comment 34 by Raymond Camden posted on 10/3/2013 at 1:56 PM

That's cool - thanks for sharing that.

Comment 35 by xavier posted on 1/17/2014 at 10:11 PM

Anyone used cfdump with customized html? What I want to do with it is use this tag for showing the results of a deep nested array of structs to an user with just the 'key' and 'values' but in a hierarchical way (format=text would be a start). Maybe, there is a UDF out there.

Comment 36 by Austin Jackson posted on 3/10/2014 at 7:58 PM

FYI - Looks like some of your images were replaced with something unrelated. Thanks Raymond!

Comment 37 by Raymond Camden posted on 3/10/2014 at 8:03 PM

I shut down coldfusionjedi.com as a separate Apache site - that would do it. I'll try and see if I can fix this post, but I don't plan on fixing *all* of them. ;)

Comment 38 by Raymond Camden posted on 3/10/2014 at 8:16 PM

Fixed - thanks.

Comment 39 (In reply to #35) by Chris Bowyer posted on 5/5/2019 at 9:17 AM

I came across this article looking for the same thing. However, after finding nothing on the web, I created the following solution.


/* Required if not using; Reset CSS, Bootstrap, etc. */
table {
border-collapse: collapse;
}
/* Removes headers; array, struct, etc. */
th {
display: none;
}
/* Fixes padding alignment issue and segregates columns for clarity */
td {
padding: 0 0 0 1px !important;
}