CakePHP4 Logging

I used to use $this->log() to log strings, arrays or objects to the debug.log file for inspection with developing and debugging. With CakePHP4, I’m replacing this with Log::debug(). However, if I try to log anything other than a string it throws a strict type error. What’s the recommend approach for logging an array or possibly on object to the debug.log file?

Use Debugger::exportVar

use Cake\Error\Debugger;

$data = [
  'a' => [....],
];
Log::debug(Debugger::exportVar($data, 6));

It shows the same output as if you do debug() on cli

1 Like

I think this is the solution

 private function convertToLogMessage(array $msg): string
    {
        return implode(', ', $msg);
    }

Log::info($this->convertToLogMessage($msg))

I hate to revive this issue, but recently ran into another problem that seems odd to me. I started using:

Log::debug(Debugger::exportVar($data, 6));

It was working great at first. I’m not sure if it’s started after updating to 4.1.1 or what. I’ve updated to 4.1.3 with no change.

Any no anytime I use this to try and log something all I get is an output of CSS and HTML. Doesn’t matter what I try to log it just out puts the same thing. I think it’s a error/debugging screen, but don’t understand why it’s outputing that instead of the variable/array/object that I want to log.

2020-08-20 20:21:19 Debug: <style type="text/css">
.cake-debug {
  --color-bg: #ECECE9;
  --color-highlight-bg: #fcf8e3;

  --color-orange: #c44f24;
  --color-green: #0b6125;
  --color-violet: #a71d5d;
  --color-blue: #4070a0;
  --color-grey: #5f5f5f;

  --color-dark-grey: #222;
  --color-cyan: #234aa0;
  --color-red: #d33c44;

  --indent: 20px;

  font-family: monospace;
  background: var(--color-bg);
  padding: 5px;
  line-height: 16px;
  font-size: 14px;
  margin-bottom: 10px;
}
.cake-debug:last-child {
  margin-bottom: 0;
}
.cake-debug > span {
  display: block;
  margin-bottom: 10px;
  color: var(--color-dark-grey);
}

.cake-dbg-object {
  display: inline;
}
.cake-dbg-object[data-highlighted=true],
.cake-dbg-object[data-highlighted=true] samp {
  background: var(--color-highlight-bg);
}

/*
Array item container and each items are blocks so
nesting works.
*/
.cake-dbg-object-props,
.cake-dbg-array-items {
  display: block;
}
.cake-dbg-prop,
.cake-dbg-array-item {
  display: block;
  padding-left: var(--indent);
  min-height: 18px;
}

/** Collapser buttons **/
[data-hidden=true] {
  display: none;
}
.cake-dbg-collapse:before {
  content: "\25b8";
  display: inline-block;
  width: 10px;
  height: 10px;
  font-size: 13px;
  line-height: 10px;
  background: hsla(0, 0%, 50%, 0.2);
  padding: 4px 2px 4px 6px;
  border-radius: 3px;
  color: var(--color-blue);
}
.cake-dbg-collapse[data-open=true]:before {
  content: "\25be";
  padding: 4px 3px 4px 5px;
}

/* Textual elements */
.cake-dbg-class {
  color: var(--color-cyan);
}
.cake-dbg-property {
  color: var(--color-dark-grey);
}
.cake-dbg-visibility {
  color: var(--color-violet);
}
.cake-dbg-punct {
  color: var(--color-grey);
}
.cake-dbg-string {
  color: var(--color-green);
  white-space: pre-wrap;
}
.cake-dbg-number {
  font-weight: bold;
  color: var(--color-blue);
}
.cake-dbg-const {
  color: var(--color-yellow);
  font-weight: bold;
}
.cake-dbg-ref {
  color: var(--color-red);
}
.cake-dbg-special {
  color: var(--color-red);
  font-style: italic;
}
</style>
<script type="text/javascript">
(function (win, doc) {

function initialize() {
  createCollapsibles(doc.querySelectorAll('.cake-dbg-array-items'));
  createCollapsibles(doc.querySelectorAll('.cake-dbg-object-props'));
  attachRefEvents(doc.querySelectorAll('.cake-dbg'));
  openBlocks(doc.querySelectorAll('.cake-debug[data-open-all="true"]'));
}
// Add a name on window so DebugKit can add controls to dump blocks
win.__cakeDebugBlockInit = initialize;

/**
 * Open all the collapsed sections in a block.
 */
function openBlocks(blocks) {
  blocks.forEach(function (block) {
    block.querySelectorAll('.cake-dbg-collapse[data-open="false"]').forEach(function (el) {
      el.click();
    });
  });
}

/**
 * Create collapse toggles and attach events
 */
function createCollapsibles(nodes) {
  nodes.forEach(function (node) {
    // Hide the childnode container if it is not
    // a direct parent of the container.
    if (!node.parentNode.parentNode.classList.contains('cake-dbg')) {
      node.dataset.hidden = true;
    }

    // Don't show toggles for empty arrays/objects
    if (node.childNodes.length == 0) {
      return;
    }

    var collapser = doc.createElement('a');
    collapser.classList.add('cake-dbg-collapse');
    collapser.dataset.open = !node.dataset.hidden;
    collapser.setAttribute('href', '#')
    collapser.setAttribute('title', 'Toggle items');

    // Add open/close behavior
    collapser.addEventListener('click', function (event) {
      event.preventDefault();
      event.stopPropagation();
      node.dataset.hidden = node.dataset.hidden === 'true' ? 'false' : 'true';
      collapser.dataset.open = collapser.dataset.open === 'true' ? 'false' : 'true';
    });

    node.parentNode.insertBefore(collapser, node);
  });
}

/**
 * When ref links are clicked open the path to that
 * element and highlight the reference
 */
function attachRefEvents(nodes) {
  nodes.forEach(function (container) {
    var refLinks = container.querySelectorAll('.cake-dbg-ref');
    refLinks.forEach(function (ref) {
      ref.addEventListener('click', function (event) {
        event.preventDefault();
        event.stopPropagation();
        var target = document.getElementById(ref.getAttribute('href').substr(1));
        openPath(container, target);
      });
    });
  });
}

function openPath(container, target) {
  // Open the target element
  var expander = target.querySelector('.cake-dbg-collapse');
  if (expander.dataset.open === 'false') {
    expander.click();
  }
  container.querySelectorAll('.cake-dbg-object').forEach(function (el) {
    el.dataset.highlighted = 'false';
  })
  target.dataset.highlighted = 'true';

  var current = target;
  // Traverse up the tree opening all closed containers.
  while (true) {
    var parent = current.parentNode;
    if (parent == container) {
      break;
    }
    if (parent.classList.contains('cake-dbg-object') || parent.classList.contains('cake-dbg-array')) {
      expander = parent.querySelector('.cake-dbg-collapse');
      if (expander.dataset.open === 'false') {
        expander.click();
      }
    }
    current = parent;
  }
}

doc.addEventListener('DOMContentLoaded', initialize);
}(window, document))
</script>
<div class="cake-dbg"><span class="cake-dbg-object" id="cake-db-object-5f3edb3fe8c552.33406134-0"><span class="cake-dbg-punct">object(</span><span class="cake-dbg-class">App\Model\Entity\Setting</span><span class="cake-dbg-punct">) id:</span><span class="cake-dbg-number">0</span><span class="cake-dbg-punct"> {</span><samp class="cake-dbg-object-props"><span class="cake-dbg-prop"><span class="cake-dbg-property">&#039;key2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-string">&#039;sdfsdfsdf&#039;</span></span><span class="cake-dbg-prop"><span class="cake-dbg-property">&#039;value2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-string">&#039;sdfsdfsdf&#039;</span></span><span class="cake-dbg-prop"><span class="cake-dbg-property">&#039;[new]&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-const">true</span></span><span class="cake-dbg-prop"><span class="cake-dbg-property">&#039;[accessible]&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;key2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-const">true</span><span class="cake-dbg-punct">,</span></span><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;value2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-const">true</span><span class="cake-dbg-punct">,</span></span></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-property">&#039;[dirty]&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;key2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-const">true</span><span class="cake-dbg-punct">,</span></span><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;value2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-const">true</span><span class="cake-dbg-punct">,</span></span></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-property">&#039;[original]&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-property">&#039;[virtual]&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-property">&#039;[hasErrors]&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-const">false</span></span><span class="cake-dbg-prop"><span class="cake-dbg-property">&#039;[errors]&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-property">&#039;[invalid]&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-property">&#039;[repository]&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-string">&#039;Settings&#039;</span></span><span class="cake-dbg-prop"><span class="cake-dbg-visibility">protected</span> <span class="cake-dbg-property">_accessible</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;key2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-const">true</span><span class="cake-dbg-punct">,</span></span><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;value2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-const">true</span><span class="cake-dbg-punct">,</span></span></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-visibility">protected</span> <span class="cake-dbg-property">_fields</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;key2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-string">&#039;sdfsdfsdf&#039;</span><span class="cake-dbg-punct">,</span></span><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;value2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-string">&#039;sdfsdfsdf&#039;</span><span class="cake-dbg-punct">,</span></span></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-visibility">protected</span> <span class="cake-dbg-property">_original</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-visibility">protected</span> <span class="cake-dbg-property">_hidden</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-visibility">protected</span> <span class="cake-dbg-property">_virtual</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-visibility">protected</span> <span class="cake-dbg-property">_dirty</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;key2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-const">true</span><span class="cake-dbg-punct">,</span></span><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;value2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-const">true</span><span class="cake-dbg-punct">,</span></span></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-visibility">protected</span> <span class="cake-dbg-property">_accessors</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;App\Model\Entity\Setting&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;get&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;key2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-string">&#039;&#039;</span><span class="cake-dbg-punct">,</span></span><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;value2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-string">&#039;&#039;</span><span class="cake-dbg-punct">,</span></span></samp><span class="cake-dbg-punct">]</span></span><span class="cake-dbg-punct">,</span></span><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;set&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;key2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-string">&#039;&#039;</span><span class="cake-dbg-punct">,</span></span><span class="cake-dbg-array-item"><span class="cake-dbg-string">&#039;value2&#039;</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-string">&#039;&#039;</span><span class="cake-dbg-punct">,</span></span></samp><span class="cake-dbg-punct">]</span></span><span class="cake-dbg-punct">,</span></span></samp><span class="cake-dbg-punct">]</span></span><span class="cake-dbg-punct">,</span></span></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-visibility">protected</span> <span class="cake-dbg-property">_new</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-const">true</span></span><span class="cake-dbg-prop"><span class="cake-dbg-visibility">protected</span> <span class="cake-dbg-property">_errors</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-visibility">protected</span> <span class="cake-dbg-property">_invalid</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-array"><span class="cake-dbg-punct">[</span><samp class="cake-dbg-array-items"></samp><span class="cake-dbg-punct">]</span></span></span><span class="cake-dbg-prop"><span class="cake-dbg-visibility">protected</span> <span class="cake-dbg-property">_registryAlias</span><span class="cake-dbg-punct"> =&gt; </span><span class="cake-dbg-string">&#039;Settings&#039;</span></span></samp><span class="cake-dbg-punct">}</span></span></div>

I don’t use Cake 4 yet.
The HTML Output is added in PR #14209

Try calling with this

$oldFormatter = Log::configInstance('exportFormatter');
Log::configInstance('exportFormatter', Cake\Error\Debug\TextFormatter::class);
Log::debug(Debugger::exportVar($data, 6));
Log::configInstance('exportFormatter', $oldFormatter);

This might be worthy of opening an issue to request a method that forces the use of TextFormatter

Checking the Debugger class I see there is a method log

Try use that for example

I think you had a few errors in your code. After fixing that it does appear to work. Here’s the code:

$oldFormatter = Debugger::configInstance('exportFormatter');
Debugger::configInstance('exportFormatter', TextFormatter::class);
Log::debug(Debugger::exportVar($test, 6));
Debugger::configInstance('exportFormatter', $oldFormatter);

Thanks for the help on this. As someone moving from CakePHP 2, this simple task has been a headache. Do you think this is worthy of an issue request? If so I’ll create one. I know there is the LogTrait, but it doesn’t work like it did in CakePHP2 (it won’t accept objects or arrays). For an easier transition I wonder if making it work like it did with version 2 would be better. I’m not sure what version 3 does.

If this code

Debugger::log($test, 'debug', 6);

Writes html in the log file, then yes I would open an issue.

If not then I would just define a function like log() thas does the code I posted.