title: How could I get a new line in custom ColdFusion log files?
body: <p>I've build a ColdFusion custom tag to log error messages and other strings, whenever I need this while developing.</p>
  
  <p>My custom tag is written in cfscript. I try to log everything I can get. Therefore I would like to log a new line whenever I append a new string to "logMessage".</p>
  
  <p>I've tried to include a variable</p>
  
  <pre><code>crlf = chr(10) &amp; chr(13);
  </code></pre>
  
  <p>but this doesn't work. I think writeLog (and corresponding cflog) are not supposed to add new lines?</p>
  
  <p>That's the reason I've tried to use a workaround (using writeLog() whenever a pipe appears), but that produces a lot of overhead, because there is such a lot of meta data evertytime I run writeLog().</p>
  
  <p>Here's my script. The first lines evaluate given attributes(like "logType" and cfcatch object) and append the values, if defined, to "logMessage". </p>
  
  <p>Please take a look down to the last lines containing the for loop.</p>
  
  <pre><code>&lt;cfscript&gt;
  logMessageDelimiter="*******************************************************";
  logMessage = "";
  fileName = application.standard_log_path &amp; application.server_name &amp; "_standardLog";
  logType = "information";
  crlf = chr(10) &amp; chr(13);
  
  if(isDefined("attributes")){    //any attribute is given
  
      if(isDefined("attributes.text")){ //a custom text is given
          logMessage &amp;= "LogMessage: " &amp; attributes.text &amp; " |" ;
      }
  
      if(isDefined("attributes.file")){   //output filename
          fileName = application.standard_log_path &amp; application.server_name &amp; "_" &amp; attributes.file;
      }
  
      if(isDefined("attributes.logType")){ //a loglevel type
          switch(attributes.logType){
              case "i":
                  logType = "information";
                  break;
              case "w":
                  logType = "warning";
                  break;
              case "e":
                  logType = "error";
                  break;
              case "f":
                  logType = "fatal";
                  break;
              default:
                  logType = "information";
          }
      }
  
      if(isDefined("attributes.catch")){ //catch object is defined
          logMessage &amp;= "CFCATCH defined: " &amp; " | ";
  
          if(isDefined("attributes.catch.detail"))
                  logMessage &amp;= "detail: "  &amp; attributes.catch.detail &amp; " | ";
          if(isDefined("attributes.catch.ErrorCode"))
                  logMessage &amp;= "ErrorCode: "  &amp; attributes.catch.ErrorCode &amp; " | ";
          if(isDefined("attributes.catch.ErrNumber"))
                  logMessage &amp;= "ErrNumber: "  &amp; attributes.catch.ErrNumber &amp; " | ";
          if(isDefined("attributes.catch.ExtendedInfo"))
                  logMessage &amp;= "QueryError: "  &amp; attributes.catch.ExtendedInfo &amp; " | ";
          if(isDefined("attributes.catch.message"))
                  logMessage &amp;= "message: "  &amp; attributes.catch.message &amp; " | ";
          if(isDefined("attributes.catch.RootCause"))
                  logMessage &amp;= "RootCause: "  &amp; attributes.catch.RootCause &amp; " | ";
          if(isDefined("attributes.catch.TagContext"))
          {
              for(i=1; i LTE ArrayLen(attributes.catch.TagContext); i=i+1)
              {
                  logMessage &amp;= "TagContext["&amp; i &amp;"] Column: " &amp; attributes.catch.TagContext[i]["Column"] &amp; " | ";
                  logMessage &amp;= "TagContext["&amp; i &amp;"] ID: " &amp; attributes.catch.TagContext[i]["ID"] &amp; " | ";
                  logMessage &amp;= "TagContext["&amp; i &amp;"] Line: " &amp; attributes.catch.TagContext[i]["Line"] &amp; " | ";
                  logMessage &amp;= "TagContext["&amp; i &amp;"] RawTrace: " &amp; attributes.catch.TagContext[i]["Raw_Trace"] &amp; " | ";
                  logMessage &amp;= "TagContext["&amp; i &amp;"] Template: " &amp; attributes.catch.TagContext[i]["Template"] &amp; " | ";
                  logMessage &amp;= "TagContext["&amp; i &amp;"] Type: " &amp; attributes.catch.TagContext[i]["Type"] &amp; " | ";
              }
          }
  
          if(isDefined("attributes.catch.Type"))
                  logMessage &amp;= "Type: "  &amp; attributes.catch.Type &amp; " | ";        
          if(isDefined("attributes.catch.NativeErrorCode"))
                  logMessage &amp;= "NativeErrorCode: "  &amp; attributes.catch.NativeErrorCode &amp; " | ";
          if(isDefined("attributes.catch.SQLState"))
                  logMessage &amp;= "SQLState: "  &amp; attributes.catch.SQLState &amp; " | ";
          if(isDefined("attributes.catch.SQL"))
                  logMessage &amp;= "SQL: "  &amp; attributes.catch.SQL &amp; " | ";
          if(isDefined("attributes.catch.QueryError"))
                  logMessage &amp;= "QueryError: "  &amp; attributes.catch.QueryError &amp; " | ";        
          if(isDefined("attributes.catch.Where"))
                  logMessage &amp;= "Where: "  &amp; attributes.catch.Where &amp; " | ";
          if(isDefined("attributes.catch.ErrNumber"))
                  logMessage &amp;= "ErrNumber: "  &amp; attributes.catch.ErrNumber &amp; " | ";          
          if(isDefined("attributes.catch.MissingFileName"))
                  logMessage &amp;= "MissingFileName: "  &amp; attributes.catch.MissingFileName &amp; " | ";
          if(isDefined("attributes.catch.MissingFileName"))
                  logMessage &amp;= "MissingFileName: "  &amp; attributes.catch.MissingFileName &amp; " | ";
          if(isDefined("attributes.catch.LockName"))
                  logMessage &amp;= "LockName: "  &amp; attributes.catch.LockName &amp; " | ";
          if(isDefined("attributes.catch.LockOperation"))
                  logMessage &amp;= "LockOperation: "  &amp; attributes.catch.LockOperation &amp; " | ";
          if(isDefined("attributes.catch.ExtendedInfo"))
                  logMessage &amp;= "ExtendedInfo: "  &amp; attributes.catch.ExtendedInfo &amp; " | ";
      }
  }
  splittedText = listToArray(logMessage,'|');
  for(i=1; i LTE ArrayLen(splittedText); i=i+1)
  {
      //I really need a better solution than this loop... 
      writeLog(splittedText[i],logType,true,fileName);
  }
  writeLog(logMessageDelimiter,logType,true,fileName);
  </code></pre>
  
  <p></p>
  
  <p>I use my custom tag like this:</p>
  
  <pre><code>&lt;cftry&gt;
    ...some buggy code
  &lt;cfcatch&gt;
    &lt;customTagName text="Hey, you've got an error!" file="myLogFile" type="e" catch="#cfcatch#"&gt;
  &lt;/cfcatch&gt;
  &lt;/cftry&gt;
  </code></pre>
  
  <p>in the logs I'll get the following output (truncated):</p>
  
  <pre><code>"Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS","LogMessage: Hey, you've got an error!"
  "Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS","CFCATCH defined:  "
  "Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS"," detail:  "
  "Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS"," ErrorCode:  "
  "Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS"," ErrNumber: 0 "
  "Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS"," QueryError:  "
  "Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS"," message: Errormessage from CF telling me my errors "
  "Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS"," TagContext[1] Column: 0 "
  "Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS"," TagContext[1] ID: CF_CFPAGE "
  "Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS"," TagContext[1] Line: 183 "
  "Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS"," TagContext[1] RawTrace:       at cffileecfm1278323672._factor2(/the/path/to/my/file.cfm:183) "
  "Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS"," TagContext[1] Template: /the/path/to/my/file.cfm"
  "Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS"," TagContext[1] Type: CFML "
  ...
  "Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS","*******************************************************"
  </code></pre>
  
  <p>So would you do? Is there a way to get a new line, without executing writeLog() over and over again.</p>
  
  <p>I would like to see a result like this:</p>
  
  <pre><code>"Information","ajp-bio-8013-exec-37118","02/11/13","14:26:09","SYS_MYSYS","LogMessage: Hey, you've got an error!"
      "CFCATCH defined:  "
      " detail:  "
      " ErrorCode:  "
      " ErrNumber: 0 "
      " QueryError:  "
      " message: Errormessage from CF telling me my errors "
      " TagContext[1] Column: 0 "
      " TagContext[1] ID: CF_CFPAGE "
      " TagContext[1] Line: 183 "
      " TagContext[1] RawTrace:       at cffileecfm1278323672._factor2(/the/path/to/my/file.cfm:183) "
      " TagContext[1] Template: /the/path/to/my/file.cfm"
      " TagContext[1] Type: CFML "
      ...
      "*******************************************************"
  </code></pre>
  
  <p>I could use methods to write into a file, but I think that's not the best way either, isn't it? In addition: I can't write to standard log folder (e.g. /path/to/coldfusion/instancename/logs/myLogFolder) of ColdFusion from within my application?!</p>
  
  <p>Is there any way to get some structure to my log files? Do you have an idea?</p>