Cannot copy msg.payload which is too long

Hello,

When I tried to copy value of the payload object , It can be copied just what is visible on the debug window. Since the value is too much , all of them cannot be seen on the debug window just ... seen in the end and I also cannot copy all.

You can change the length in settings.js but setting it too long will likely cause the editor to slow down. I think if you change the debug node to output to log, you will get the full thing as well but that isn't terribly convenient.

I recently also had problems like this and ended up having to output direct to a file-out node.

Or you could use this subflow to send the msg to a separate browser window, you can then copy the message.

1 Like

:slight_smile:

And if anyone wants a uibuilder flow that will do that, let me know. (hint - no code and no subflow required).

1 Like

Yes please.

1 Like

OK, here is the REALLY simple one :slight_smile:

However, it doesn't quite match E1cid's subflow - I'll do a better one tomorrow.

  1. Add a uibuilder node and give it a URL of debug. Deploy. (no other settings needed).
  2. Add an inject node configured as shown below connected to the uibuilder input.
  3. Inject.
  4. Open the uibuilder page.
  5. Send a message to the uibuilder node who's contents you want to copy.

{"command":"showMsg"}

That's it! You can copy the output of the msg box that is shown and even resize the box for convenience. Every msg sent to the uibuilder node will be shown but there is no history, only the last msg is shown. The output is formatted for ease of reading though:

As I said, no code needed. :slight_smile: Though if you want to, you can turn on the msg box in the front-end code so that it is always on rather than having to turn it on.

3 Likes

OK, as promised, here is a more complete example of a debug page using uibuilder.

[{"id":"38dea932ad8bf5b0","type":"group","z":"30fdd9a9702231b0","name":"uibuilder Node-RED debug page - with full output and copy (Read my description for details)","style":{"label":true,"fill":"#ffefbf","fill-opacity":"0.34","color":"#000000"},"nodes":["b2b9cd88db08056f","30f917ba22b7601a","465991cb13575bdc","2dcf170369271854","85e33c87a851fd7b","cd117dec98696547"],"env":[{"name":"debug_name","value":"Debug","type":"str"},{"name":"debug_property","value":"msg","type":"str"}],"x":514,"y":99,"w":578,"h":142,"info":"A simple debug output page using uibuilder.\r\n\r\nNote that this group has 2 defined environment\r\nvariables. \r\n\r\n`debug_name` and `debug_property`. These\r\ncan also be overridden using msg properties\r\nof the same name.\r\n\r\nSimple send any message to the `link-in` node\r\nin this group and view a formatted version of\r\nthe message on the debug web page.\r\n\r\nThe web page has pause/resume buttons and \r\nclear all entries buttons.\r\n\r\nEach entry on the page can be copied to the \r\nclipboard using the ❒ button. Or the entry \r\ncan be deleted using the ❌ button.\r\n\r\nThe formatted output for each entry appears in \r\na scrollable box. You can grab the bottom-right\r\ncorner and expand the box manually.\r\n\r\nUnlike Node-RED's debug panel, ALL of the msg\r\nobject is included in the output - up to the \r\nmax limit of the Socket.IO client. If you need\r\nto extend the limit, you can do so in the \r\nuibuilder settings in the `settings.js` file.\r\n\r\nHowever, as with any web app, be wary of How\r\nmuch data you keep in the browser window. If \r\nyou let it get too big, your browser will slow\r\ndown and eventually break."},{"id":"b2b9cd88db08056f","type":"function","z":"30fdd9a9702231b0","g":"38dea932ad8bf5b0","name":"","func":"// What msg property to debug (or the whole msg)\nconst debug_property = msg.debug_property || env.get('debug_property') || 'msg'\n// Each property part as an array. e.g `msg._ui` becomes ['msg','_ui']\nlet debug_property_array = []\n// Record any errors\nlet err = []\n\nlet dt = (new Date()).toLocaleString()\n\ntry {\n  debug_property_array = RED.util.normalisePropertyExpression(debug_property)\n  // node.send([null, {debug_property, debug_property_array}])\n} catch (e) {\n  node.warn(e.message)\n  err.push(e.message)\n}\n\nlet msg1 = {data: null}\ntry {\n  // Try to get a specific msg property if requested\n  let ans = RED.util.getMessageProperty(msg, debug_property)\n  if (ans === undefined) {\n    err.push(`Message property not found. '${debug_property}'`)\n  } else {\n    msg1.data = ans\n  }\n} catch(e) {\n  // Else get the whole msg\n  msg1.data = RED.util.cloneMessage(msg)\n  // but remove the debug meta data if it was passed in on the orig msg\n  delete msg1.data.debug_name\n  delete msg1.data.debug_property\n  delete msg1.data.pass_debug_property\n  delete msg1.data.debug_array\n  err.push(e.message)\n}\n\nmsg1.topic = msg.topic\nmsg1.errors = err\nmsg1.debug_property = debug_property\nmsg1.debug_property_array = debug_property_array\n// Optional msg name - will default to original msg id\nmsg1.debug_name = msg.debug_name || env.get(\"debug_name\") || msg._msgid || \"name error\"\nmsg1.debug_dt = dt\n\nreturn [msg1,msg]","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":700,"y":140,"wires":[["30f917ba22b7601a"],[]],"inputLabels":["msg to debug"],"outputLabels":["debug msg","Original msg"]},{"id":"30f917ba22b7601a","type":"uibuilder","z":"30fdd9a9702231b0","g":"38dea932ad8bf5b0","name":"","topic":"","url":"debug","fwdInMessages":false,"allowScripts":false,"allowStyles":false,"copyIndex":true,"templateFolder":"blank","extTemplate":"","showfolder":false,"reload":false,"sourceFolder":"src","deployedVersion":"6.5.0","showMsgUib":false,"x":960,"y":140,"wires":[[],[]]},{"id":"465991cb13575bdc","type":"link in","z":"30fdd9a9702231b0","g":"38dea932ad8bf5b0","name":"link in 13","links":["0919ecfaa892d896","e81d0d1c57d90da7"],"x":555,"y":140,"wires":[["b2b9cd88db08056f"]]},{"id":"2dcf170369271854","type":"comment","z":"30fdd9a9702231b0","g":"38dea932ad8bf5b0","name":"index.html","info":"<!doctype html>\n<html lang=\"en\"><head>\n\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"icon\" href=\"../uibuilder/images/node-blue.ico\">\n\n    <title>Debug - Node-RED uibuilder</title>\n    <meta name=\"description\" content=\"Node-RED uibuilder - Debug\">\n\n    <!-- Your own CSS (defaults to loading uibuilders css)-->\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"./index.css\" media=\"all\">\n\n    <!-- #region Supporting Scripts. These MUST be in the right order. Note no leading / -->\n    <script defer src=\"../uibuilder/uibuilder.iife.min.js\"></script>\n    <script defer src=\"./index.js\">/* OPTIONAL: Put your custom code in that */</script>\n    <!-- #endregion -->\n\n</head><body class=\"uib\">\n    <h1 class=\"with-subtitle\">uibuilder - Debug</h1>\n    <div role=\"doc-subtitle\">Using the IIFE library.</div>\n\n    <div id=\"header\">\n        <button id=\"pauser1\" value=\"pause\" onclick=\"doPause(event)\">Pause</button>\n        <button onclick=\"doClear(event)\">Clear All</button>\n    </div>\n\n    <div id=\"more\"><!-- '#more' is used as a parent for dynamic HTML content in examples --></div>\n\n    <div id=\"footer\">\n        <button id=\"pauser2\" value=\"pause\" onclick=\"doPause(event)\">Pause</button>\n        <button onclick=\"doClear(event)\">Clear All</button>\n    </div>\n\n</body></html>\n","x":600,"y":200,"wires":[]},{"id":"85e33c87a851fd7b","type":"comment","z":"30fdd9a9702231b0","g":"38dea932ad8bf5b0","name":"index.js","info":"// uibuilder.logLevel = 2 // info\n\nconst elPaused1 = document.getElementById(\"pauser1\") || {innerText:''}\nconst elPaused2 = document.getElementById(\"pauser2\") || {innerText:''}\nlet paused = false\nlet msgCount = 0\n\n// Stop/resume inbound msgs\nfunction doPause(event) {\n    if (paused === true) {\n        elPaused1.innerText = \"Pause\"\n        elPaused2.innerText = \"Pause\"\n        paused = false\n        uibuilder.log('info', 'uibuilder.debug', 'Visual debug messages flowing')\n    } else {\n        elPaused1.innerText = \"Resume\"\n        elPaused2.innerText = \"Resume\"\n        paused = true\n        uibuilder.log('info', 'uibuilder.debug', 'Visual debug messages paused')\n    }\n}\n\n// Remove the selected debug entry\nfunction cpy(event) {\n    const elToCopy = event.target.parentElement.parentElement.querySelector('pre')\n    window.prompt(\"Copy to clipboard: Ctrl+C, Enter\", elToCopy.innerText)\n}\n\nfunction del(event) {\n    event.target.parentElement.parentElement.remove()\n}\n\n// Clears all debug entries\nfunction doClear(event) {\n    document.querySelector('#more').textContent = ''\n}\n\nuibuilder.onChange('msg', (msg) => {\n    console.log('DEBUG msg', msg)\n\n    if (paused === true || msg._ui) return\n\n    ++msgCount\n\n    // use uibuilder's low-code capability to build the output structure for the new debug entry\n    const toAdd = [{\n        method: 'add',\n        components: [\n            {\n                type: 'article',\n                parent: '#more',\n                position: 'first',\n                id: `dbg_${msgCount}`,\n                attributes: {\n                    class: 'dbg',\n                },\n                components: [\n                    {\n                        type: 'div',\n                        slot: `#${msgCount} | ${msg.debug_name} | ${msg.debug_dt} | <i title=\"msg property\">${msg.debug_property}</i> | <button title=\"copy\" onclick=\"cpy(event)\"> &#10066; </button><button title=\"delete\" onclick=\"del(event)\"> &#10060; </button> `,\n                    },\n                ],\n            }\n        ],\n\n    }]\n\n    // If there are errors, output a list of them\n    if (msg.errors.length > 0) {\n        toAdd[0].components[0].components.push({\n            type: 'div',\n            slot: `<p class=\"error\">${msg.errors.join('</p><p class=\"error\">')}</p>`\n        })\n    } else {\n        // otherwise output the msg.data highlighted\n        toAdd[0].components[0].components.push({\n            type: 'pre',\n            attributes: {\n                class: 'syntax-highlight',\n            },\n            // Formates the data using a simple JSON colour formatter\n            slot: uibuilder.syntaxHighlight(msg.data)\n        })\n    }\n\n    uibuilder.ui(toAdd)\n})\n","x":730,"y":200,"wires":[]},{"id":"cd117dec98696547","type":"comment","z":"30fdd9a9702231b0","g":"38dea932ad8bf5b0","name":"index.css","info":"/* Load defaults from `<userDir>/node_modules/node-red-contrib-uibuilder/front-end/uib-brand.css`\n * This version auto-adjusts for light/dark browser settings but might not be as complete.\n */\n@import url(\"../uibuilder/uib-brand.css\");\n\n#header {\n    margin-bottom: 1em;\n    padding-bottom: .5em;\n    border-bottom: 1px solid silver;\n}\n#footer {\n    margin-top: 1em;\n    padding-top: .5em;\n    border-top: 1px solid silver;\n}\n.dbg {\n    border: 1px solid silver;\n    padding: 1rem;\n}\n","x":860,"y":200,"wires":[]}]

Simply import the flow, deploy then use the 3 comment nodes to replace the index.html, javascript and css files. After that, you can open the page and send msgs to the link-in node in the provided group.

Read the group's description for more details.

And of course, feel free to tweak to your own needs. :slight_smile:

This flow is now also available in the flows library:

A debug tool for Node-RED using uibuilder (flow) - Node-RED (nodered.org)

4 Likes

It is working perfectly , thanks for your help

Thank you for your help

I really must thank you for this. It's an awesome way to help with debugging rather large messages in a manageable and readable way. Being able to pack the entire msg in and get syntax highlighting and proper formatting is pure bliss.

1 Like

Not a problem. But just to make things even better (as I'm using this myself now), here is an updated version that is more compact and lets you do things like toggle on/off the json block.

[{"id":"38dea932ad8bf5b0","type":"group","z":"ff1a7711.244f48","name":"uibuilder Node-RED debug page - with full output and copy (Read my description for details)","style":{"label":true,"fill":"#ffefbf","fill-opacity":"0.34","color":"#000000"},"nodes":["b2b9cd88db08056f","30f917ba22b7601a","465991cb13575bdc","2dcf170369271854","85e33c87a851fd7b","cd117dec98696547"],"env":[{"name":"debug_name","value":"Debug","type":"str"},{"name":"debug_property","value":"msg","type":"str"}],"x":34,"y":319,"w":578,"h":142,"info":"A simple debug output page using uibuilder.\r\n\r\nNote that this group has 2 defined environment\r\nvariables. \r\n\r\n`debug_name` and `debug_property`. These\r\ncan also be overridden using msg properties\r\nof the same name.\r\n\r\nSimple send any message to the `link-in` node\r\nin this group and view a formatted version of\r\nthe message on the debug web page.\r\n\r\nThe web page has pause/resume buttons and \r\nclear all entries buttons.\r\n\r\nEach entry on the page can be copied to the \r\nclipboard using the ❒ button. Or the entry \r\ncan be deleted using the ❌ button.\r\n\r\nThe formatted output for each entry appears in \r\na scrollable box. You can grab the bottom-right\r\ncorner and expand the box manually.\r\n\r\nUnlike Node-RED's debug panel, ALL of the msg\r\nobject is included in the output - up to the \r\nmax limit of the Socket.IO client. If you need\r\nto extend the limit, you can do so in the \r\nuibuilder settings in the `settings.js` file.\r\n\r\nHowever, as with any web app, be wary of How\r\nmuch data you keep in the browser window. If \r\nyou let it get too big, your browser will slow\r\ndown and eventually break."},{"id":"b2b9cd88db08056f","type":"function","z":"ff1a7711.244f48","g":"38dea932ad8bf5b0","name":"","func":"// What msg property to debug (or the whole msg)\nconst debug_property = msg.debug_property || env.get('debug_property') || 'msg'\n// Each property part as an array. e.g `msg._ui` becomes ['msg','_ui']\nlet debug_property_array = []\n// Record any errors\nlet err = []\n\nlet dt = (new Date()).toLocaleString()\n\ntry {\n  debug_property_array = RED.util.normalisePropertyExpression(debug_property)\n  // node.send([null, {debug_property, debug_property_array}])\n} catch (e) {\n  node.warn(e.message)\n  err.push(e.message)\n}\n\nlet msg1 = {data: null}\nif (debug_property === 'msg') {\n  // Get the whole msg\n  msg1.data = RED.util.cloneMessage(msg)\n} else {\n  try {\n    // Try to get a specific msg property if requested\n    let ans = RED.util.getMessageProperty(msg, debug_property)\n    if (ans === undefined) {\n      err.push(`Message property not found. '${debug_property}'`)\n    } else {\n      msg1.data = ans\n    }\n  } catch(e) {\n    // Else get the whole msg\n    msg1.data = RED.util.cloneMessage(msg)\n    // but remove the debug meta data if it was passed in on the orig msg\n    delete msg1.data.debug_name\n    delete msg1.data.debug_property\n    delete msg1.data.pass_debug_property\n    delete msg1.data.debug_array\n    err.push(e.message)\n  }\n}\n\nmsg1.topic = msg.topic\nmsg1.errors = err\nmsg1.debug_property = debug_property\nmsg1.debug_property_array = debug_property_array\n// Optional msg name - will default to original msg id\nmsg1.debug_name = msg.debug_name || env.get(\"debug_name\") || msg._msgid || \"name error\"\nmsg1.debug_dt = dt\n\nreturn [msg1,msg]","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":220,"y":360,"wires":[["30f917ba22b7601a"],[]],"inputLabels":["msg to debug"],"outputLabels":["debug msg","Original msg"]},{"id":"30f917ba22b7601a","type":"uibuilder","z":"ff1a7711.244f48","g":"38dea932ad8bf5b0","name":"","topic":"","url":"debug","fwdInMessages":false,"allowScripts":false,"allowStyles":false,"copyIndex":true,"templateFolder":"blank","extTemplate":"","showfolder":false,"reload":false,"sourceFolder":"src","deployedVersion":"6.5.0","showMsgUib":false,"x":480,"y":360,"wires":[[],[]]},{"id":"465991cb13575bdc","type":"link in","z":"ff1a7711.244f48","g":"38dea932ad8bf5b0","name":"DEBUG","links":["e1e4747c8aa0481c"],"x":75,"y":360,"wires":[["b2b9cd88db08056f"]]},{"id":"2dcf170369271854","type":"comment","z":"ff1a7711.244f48","g":"38dea932ad8bf5b0","name":"index.html","info":"<!doctype html>\n<html lang=\"en\">\n\n<head>\n\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"icon\" href=\"../uibuilder/images/node-blue.ico\">\n\n    <title>Debug - Node-RED uibuilder</title>\n    <meta name=\"description\" content=\"Node-RED uibuilder - Debug\">\n\n    <!-- Your own CSS (defaults to loading uibuilders css)-->\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"./index.css\" media=\"all\">\n\n    <!-- #region Supporting Scripts. These MUST be in the right order. Note no leading / -->\n    <script defer src=\"../uibuilder/uibuilder.iife.min.js\"></script>\n    <script defer src=\"./index.js\">\n        /* OPTIONAL: Put your custom code in that */\n    </script>\n    <!-- #endregion -->\n\n</head>\n\n<body class=\"uib\">\n    <h1 class=\"with-subtitle\">uibuilder - Debug</h1>\n    <div role=\"doc-subtitle\">Using the IIFE library.</div>\n\n    <div id=\"header\">\n        <button id=\"pauser1\" value=\"pause\" onclick=\"doPause(event)\">Pause</button>\n        <button onclick=\"doClear(event)\">Clear All</button>\n        <button onclick=\"doToggle(event)\">Toggle All</button>\n    </div>\n\n    <div id=\"more\">\n        <!-- '#more' is used as a parent for dynamic HTML content in examples -->\n    </div>\n\n    <div id=\"footer\">\n        <button id=\"pauser2\" value=\"pause\" onclick=\"doPause(event)\">Pause</button>\n        <button onclick=\"doClear(event)\">Clear All</button>\n        <button onclick=\"doToggle(event)\">Toggle All</button>\n    </div>\n\n</body>\n\n</html>","x":120,"y":420,"wires":[]},{"id":"85e33c87a851fd7b","type":"comment","z":"ff1a7711.244f48","g":"38dea932ad8bf5b0","name":"index.js","info":"// uibuilder.logLevel = 2 // info\n\nconst elPaused1 = document.getElementById(\"pauser1\") || { innerText: '' }\nconst elPaused2 = document.getElementById(\"pauser2\") || { innerText: '' }\nlet paused = false\nlet msgCount = 0\n\n// Stop/resume inbound msgs\nfunction doPause(event) {\n    if (paused === true) {\n        elPaused1.innerText = \"Pause\"\n        elPaused2.innerText = \"Pause\"\n        paused = false\n        uibuilder.log('info', 'uibuilder.debug', 'Visual debug messages flowing')\n    } else {\n        elPaused1.innerText = \"Resume\"\n        elPaused2.innerText = \"Resume\"\n        paused = true\n        uibuilder.log('info', 'uibuilder.debug', 'Visual debug messages paused')\n    }\n}\n\n// Clears all debug entries\nfunction doClear(event) {\n    document.querySelector('#more').textContent = ''\n}\n\n// Toggle Hide/Show all syntax-highlight boxes\nfunction doToggle(event) {\n    const els = event.target.parentElement.parentElement.querySelectorAll('pre.compact.syntax-highlight')\n    els.forEach( el => {\n        if (el.offsetWidth > 0) el.style.display = 'none'\n        else el.style.display = 'block'\n    })\n}\n\n// Copy the selected debug entry text to the browser OS clipboard\nfunction cpy(event) {\n    const elToCopy = event.target.parentElement.parentElement.querySelector('pre')\n    window.prompt(\"Copy to clipboard: Ctrl+C, Enter\", elToCopy.innerText)\n}\n// Remove the selected debug entry\nfunction del(event) {\n    event.target.parentElement.parentElement.remove()\n}\n// Toggle hide/show syntax-highlight for selected debug entry\nfunction toggle(event) {\n    const el = event.target.parentElement.parentElement.querySelector('pre')\n    if (el.offsetWidth > 0) el.style.display = 'none'\n    else el.style.display = 'block'\n}\n\nuibuilder.onChange('msg', (msg) => {\n    // console.log('DEBUG msg', msg)\n\n    if (paused === true || msg._ui) return\n\n    ++msgCount\n\n    // use uibuilder's low-code capability to build the output structure for the new debug entry\n    const toAdd = [{\n        method: 'add',\n        components: [\n            {\n                type: 'article',\n                parent: '#more',\n                position: 'first',\n                id: `dbg_${msgCount}`,\n                attributes: {\n                    class: 'dbg',\n                },\n                components: [\n                    {\n                        type: 'div',\n                        slot: `#${msgCount} | ${msg.debug_name} | ${msg.debug_dt} | <i title=\"msg property\">${msg.debug_property}</i> | <button title=\"copy\" class=\"cbtn\" onclick=\"cpy(event)\"> 📋 </button> <button title=\"toggle\" class=\"cbtn\" onclick=\"toggle(event)\"> ⬇️ </button> <button title=\"delete\" class=\"cbtn fr\" onclick=\"del(event)\"> 🗑️ </button>`,\n                    },\n                ],\n            }\n        ],\n\n    }]\n\n    // If there are errors, output a list of them\n    if (msg.errors.length > 0) {\n        toAdd[0].components[0].components.push({\n            type: 'div',\n            slot: `<p class=\"error\">${msg.errors.join('</p><p class=\"error\">')}</p>`\n        })\n    } else {\n        // otherwise output the msg.data highlighted\n        toAdd[0].components[0].components.push({\n            type: 'pre',\n            attributes: {\n                class: 'compact syntax-highlight',\n            },\n            // Formates the data using a simple JSON colour formatter\n            slot: uibuilder.syntaxHighlight(msg.data)\n        })\n    }\n\n    uibuilder.ui(toAdd)\n})\n","x":250,"y":420,"wires":[]},{"id":"cd117dec98696547","type":"comment","z":"ff1a7711.244f48","g":"38dea932ad8bf5b0","name":"index.css","info":"/* Load defaults from `<userDir>/node_modules/node-red-contrib-uibuilder/front-end/uib-brand.css`\n * This version auto-adjusts for light/dark browser settings but might not be as complete.\n */\n@import url(\"../uibuilder/uib-brand.css\");\n\n#header {\n    margin-bottom: 0;\n    padding-bottom: .5em;\n    border-bottom: 1px solid var(--surface5);\n}\n#footer {\n    margin-top: 1em;\n    padding-top: .5em;\n    border-top: 1px solid var(--surface5);\n}\n.dbg {\n    border: 1px solid var(--surface5);\n    padding: 0.2rem 0.5rem;\n    margin: 0;\n}\n.cbtn {\n    padding: 2px 5px;\n    border-radius: 0;\n    background: inherit;\n    margin: 2px;\n}\n.compact {\n    margin: 0;\n    padding-top: 0.2rem;\n    padding-bottom: 0.2rem;\n}\n.fr {\n    float: right;\n}","x":380,"y":420,"wires":[]}]

Oh, and the action icons are a bit nicer too. :grin:

This will probably also become a uibuilder example as well in the next release.

It's like you read my mind

I submitted an example flow awhile back with the eventual intention of creating something similar to this but I doubt the quality and feature set of mine would have be nearly as great as this. I would love to see it become an example flow that sticks around.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.