Output ANSI formatting in your server log

Ben Nadel recently asked me on Twitter if he could put colored text in his server’s console log.

The answer is “yes”, but comes with a few clarifications. Firstly, the standard out of a server (or any process for that matter) is simply a string of bytes (usually text). Only in the context of a Terminal which displays the text and has a concept of ANSI escape codes, will color be displayed. So, if you’re a CommandBox user, this means a server started like so:

server start --console

or tailing the console log for an already-running server like so:

server log --follow

from within CommandBox will automatically render any ANSI escape sequences in the text.

ANSI escapes are hard to read, and certainly not designed for humans to consume, but they are fairly well documented. Here is an example of how to do it. Simply place this code inside your web app:

esc = chr( 27 );
ANSIMessage = "-" & ESC & "[38;5;50m" & "my message" & ESC & "[0m";
systemoutput( ANSIMessage, true );

which outputs this:

Let’s break this down:

  • It isn’t necessary to put chr( 27 ) into a variable, I’m just used to doing it for readability.
  • I have two escape sequence, one to turn on a color and one to turn it back OFF so it doesn’t bleed into the next line.
  • Using ^ to represent an escape byte (ASCII code 27), the first sequence is ^[38;5;50m which turns the text foreground to “Cyan2” (color ID 50) which I chose at random for this example.
  • The second sequence is ^[0m which turns off all previously set decoration

It’s worth noting that the number 50 is an ANSI standard, while the word cyan2 (as well as the JSON file I link to below) is arbitrarily assigned and based on a list I found online that maps color numbers to human-friendly names.

There are 256 colors you can choose from to set both the foreground and background color in addition to

  • bold
  • blinking (only works on Mac terminals from my testing)
  • underscore (not supported on all terminals)
  • reversed (it swaps the foreground and background color)

And I should also add, that the code above is specific to Lucee Server as it uses the systemOutput() BIF. You can also do this on Adobe CF like so:

createObject( 'java', 'java.lang.System' ).out.println( ANSIMessage );

Now, a few caveats:

  • The - at the start of the message is required and must be before any ANSI escapes. This is due to an unfortunate behavior inside CommandBox that trims all log messages and accidentally removes the leading escape char if it’s the first thing in the string. I’ll remove that trim in the next version of CommandBox. COMMANDBOX-1483
  • The raw ANSI escapes will show up in your server’s text log file when you open it in Notepad or similar and will look like this: ^[38;5;50mmy message^[0m (I’m using the ^ char to represent ASCII code 27, but your favorite text editor may use something different)
  • Any other tools used to parse console logs for your server including Docker, or Elastic APM, etc may or may not have a way to interpret the ANSI escapes. That’s just a risk you take-- it won’t hurt anything, it just may be ugly.

Now finally, you can create some easy little wrappers to help generate the ANSI escapes for you, but if you really want to make a habit of this, I’d recommend we take a few minutes to extract out the print helper from inside of CommandBox which provides a very nice DSL for outputting text with ANSI escape codes.

print.text( 'Hello World' );
print.boldText( 'Hello World' );
print.line( 'Hello World' );
print.redLine( 'Hello World' );
print.redOnWhiteLine( 'Hello World' );
print.redOnWhiteBold( 'Hello World' );
print.boldBlinkingUnderscoredBlueTextOnRedBackground( 'Test' );

The print class currently has some dependencies on CommandBox, but that could be remedied fairly easily. I’ve just never had a reason to use it outside of CommandBox until now. commandbox/Print.cfc at development · Ortus-Solutions/commandbox · GitHub

That class above provides for

  • a DSL-based shortcut for applying all ANSI escape sequences
  • automatic colored output of complex values as JSON
  • CommandBox’s table printer for outputting queries or arrays of objects in a tabular format.