Skip to main content
Ben Nadel at CFUNITED 2009 (Lansdowne, VA) with: Luis Majano
Ben Nadel at CFUNITED 2009 (Lansdowne, VA) with: Luis Majano

Making CFDump Easier To Read As I Get Older

By
Published in Comments (9)

After decades of staring at a screen, my eyes aren't what they used to be. In most digital contexts, I immediately increase the font-size by 10-20% before I do anything else. This "maturing" has made me acutely aware of how absurdly small the output from Adobe ColdFusion's CFDump and writeDump() functions are. I know that some developers use custom implementations of CFDump in order to exert more control. But for the moment, I'm trying to keep it simple. To that end, my approach to increasing the readability of the CFDump output is to inject a <style> tag that overrides Adobe's styles using CSS specificity.

When you run the writeDump() function or execute the CFDump tag, Adobe ColdFusion magically injects <style> and <script> tags into the <head> of your page. Normally, I don't like magic in my code; but, since they're using magic, I'm going to use magic as well, in the form of the CFHtmlHead tag.

Aside: I consider the CFHtmlHead tag to be an anti-pattern because it operates outside the visible universe of your code. Meaning, if you follow the processing of an incoming request, down through the routing and the layout selection, you'll never actually see how CFHtmlHead gets code into the page output. Because it's magic — black magic.

In my Big Sexy Poems app, I have a CFML extensions file (cfmlx.cfm) that I use to polyfill functions. One of the functions that I polyfill is Lucee CFML's dump() method. As such, modifying the behavior of the dump() method can be completely transparent to the rest of my ColdFusion application because it's already something I'm proxying.

To improve the output of the dump() call, I'm going to check to see if the output is the "browser" (as opposed to the "console" or a "file"); and, if so, I'll use the CFHtmlHead tag to inject some overriding CSS.

Here's a snippet of my cfmlx.cfm file - it contains my dump() polyfill and the dumpStyles() helper method:

<cfscript>

	/**
	* I polyfill the dump() function in Adobe ColdFusion.
	*/
	private void function dump(
		required any var,
		boolean expand = true,
		string format = "html",
		string hide = "",
		numeric keys = 9999,
		string label = "",
		string output = "browser",
		string show = "all",
		boolean showUDFs = true,
		numeric top = 9999,
		boolean abort = false
		) {

		// Note: under the hood, Adobe ColdFusion seems to be compiling this down into an
		// instance of the CFDump tag (based on error messages). As such, it's much more
		// temperamental than a normal function invocation (include my attempts at using
		// the argumentCollection construct). We have to be much more explicit in our
		// argument pass-through; and, certain attributes CANNOT be passed in as NULL.
		writeDump(
			var = var,
			expand = expand,
			format = format,
			hide = hide,
			keys = keys,
			label = label,
			output = output,
			show = show,
			showUDFs = showUDFs,
			top = top,
			abort = abort
		);

		// If we're outputting to the browser (the default behavior), inject custom styles
		// for better readability for my aging eyes.
		if ( output == "browser" ) {

			dumpStyles();

		}

	}

	/**
	* I inject style tags that make the CFDump output easier to read.
	*/
	private void function dumpStyles() {

		// For better debugging on how these styles are being injected, we're going to
		// include the call-stack in the style tag content (as a comment).
		var stacktrace = callStackGet()
			.map( ( frame ) => "- #frame.template#:#frame.lineNumber#" )
			.toList( chr( 10 ) & repeatString( chr( 9 ), 4 ) & "* " )
		;

		// CAUTION: Normally, the use of cfhtmlhead() is considered an ANTI-PATTERN due to
		// its total lack of accountability. But, in this case, we're fighting fire with
		// fire. Meaning, the writeDump() tag is already injecting styles magically; and
		// now, we're also injecting styles magically to counteract their magical styles.
		cfhtmlhead( text = "
			<style type='text/css' data-source='Added by the dumpStyles().'>
				/**
				* ColdFusion Stacktrace:
				* #stacktrace#
				**/

				html body table[class^='cfdump_'] {
					border-collapse: separate ;
					border-spacing: 2px ;
					font-family: verdana, arial, helvetica, sans-serif ;
					margin-bottom: 1.5rem ;

					& table[class^='cfdump_'] {
						margin-bottom: 0 ;
					}

					& th,
					& td {
						font-size: 1rem ;
						padding: 0.4em 0.55em ;
					}
				}
			</style>
		");

	}

</cfscript>

Now, if I call the dump() method and look at the page output, I'll see several "magically injected" tags: two from Adobe ColdFusion and one from me:

Instead of using the !important flag in my CSS, I'm simply increasing the specificity of my style blocks by including html body in my selectors.

To demonstrate the drastic different in font-size, I'm going dump-out an array-of-structs. First, using ColdFusion's native writeDump() method:

<cfscript>

	writeDump([
		{ id: 1, name: "Kim",  role: "Admin" },
		{ id: 2, name: "Jon",  role: "Engineer" },
		{ id: 3, name: "Kali", role: "Manager" },
	]);

</cfscript>

... and second, using my dump() polyfill with dumpStyles() side-effect:

<cfscript>

	// ColdFusion language extensions (global functions).
	include "/core/cfmlx.cfm";

	// Note: this is the dump() POLYFILL I've created in the CFMLX template.
	dump([
		{ id: 1, name: "Kim",  role: "Admin" },
		{ id: 2, name: "Jon",  role: "Engineer" },
		{ id: 3, name: "Kali", role: "Manager" },
	]);

</cfscript>

And now, the output of these two dumps rendered side-by-side:

Side by side comparison of the native writeDump() rendering vs. the dump() polyfill rendering.

The one of the left looks like squiggles to me. The one on the right is readable.

This only works if I use my dump() polyfill. But, the nice thing about putting the style-injection into its own dumpStyles() function is that I can, in theory, use it alongside the native writeDump() function or CFDump tag, as long as I remember to call the dumpStyles() method at some point.

Want to use code from this post? Check out the license.

Reader Comments

16,109 Comments

Over on Facebook, James Moberg noted that calling dump() multiple times will result in multiple <style> tags getting injected. This is true; but, at the very least, it shouldn't be an issue. Each CSS property block should just overwrite the previous one (or rather, since it has the same selector specificity, they will all apply).

I use this locally, so I'm not too concerned about this.

1 Comments

Thank you so much Ben!
My eyes have been having a hard time reading the cfdumps for a while now, and I've had to resort to magnifying my window to 130%.
I'm glad to know I'm not the only one with this experience.

I'm going to try your solution, for sure!
Cheers!

16,109 Comments

@Bobby,

I think back to the early days in my career when people were all designing UIs with 11px fonts. And then there were font families that were designed to be readable at even smaller sizes! What were thinking?!?!? 😱

3 Comments

Hey Ben,

This is what I use :-) Makes my eyes happy.

table[class*="cfdump"] * {
 font-family: "JetBrains Mono", Consolas, monospace;
 font-size: .875rem;
 line-height: 1.42;
 vertical-align: top;
}
30 Comments

@ben,

Don't know how CFC's work in practice…Can you address the multiple STYLE tags by tracking how often dump has been called with a private variable within the CFC, and only output the STYLE tag the first time?

16,109 Comments

@Danilo,

Absolutely. I could just put some sort of flag in the request scope and then early-exit out of the dumpStyles() function it's already been set. I might add that. Then again, I might not since I'll only ever dump-out to the screen in development, never in production. So, a little extra cruft won't matter too much.

As an aside, though, one thing I discovered when I was doing the ColdFusion 2025 Hackathon project is that if the new CSP (Content Security Policy) headers are enabled, then CFDump breaks because the injected Style and Script tags don't include the proper nonce. I'm only pointing that out here because my style tag will also break for the same reason.

Post A Comment — I'd Love To Hear From You!

Post a Comment

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel
Managed hosting services provided by:
xByte Cloud Logo