Console and network

The playground has a console and a network panel of its own. They show what the output logs, what its workers log and which requests pass through its service worker, with a counter for each level of log. This guide shows how to open them, what reaches them, how to read a console fingerprint to compare runs, and where the same console lands in the agent folder during an Agent Folder Share.

Opening the panels

The console is a page on its own origin, co.rtcode.io, which the playground shows in a panel that overlays the page. It is built on Eruda, with the Console, Network and Info tools, in a dark theme.

WayWhat it opens
The πŸ“œ button in the toolbarA click opens the Console with every level. A right click opens Network. A level badge next to it opens that level's view.
F12Outside the editor, it toggles the panel. In the editor it runs Developer Tools β†’ Console. While the input or the output is fullscreen, it does not toggle the console.
F9Developer Tools β†’ Network.
Alt+; / βŒ₯+;Toggles the panel.
The URLc=1 reopens the Console on load and c=2 the Network panel. ch=1 hides the πŸ“œ button and its badges.

Opening the view that is already showing closes the panel, and choosing another view switches to it. The Γ— buttons close it, with the tooltip "Console F12". Drag the divider of the panel to resize it. Ctrl+; / βŒƒ+; focuses that divider, and ; on the focused divider returns to the editor. While the pointer is over the divider between the input and the output, the console fades to 10% opacity after 0.3 seconds.

Experimental From a script, c.open = 0, 1 or 2 closes the panel or opens the Console or the Network panel. c.show.console({ level }), c.show.network(), c.hide(), c.console.clear() and c.network.clear() do what their names say.

Counters

Badges next to the πŸ“œ button count what the console received. A badge pulses when its count changes, and the group is hidden while every count is empty.

BadgeCounts
logconsole.log(), and every method without a badge of its own.
infoconsole.info().
debugconsole.debug().
warnconsole.warn().
errorconsole.error(), and failed console.assert() calls.
networkEach request in the Network panel.

These calls are not counted: countReset, profile, profileEnd, time, timeStamp, groupEnd, and passing assertions. console.clear() empties every badge, the network badge too. Opening the panel from a badge filters it: log and info show the "info" level, warn shows "warning", error shows "error", and debug and the full view show "all".

What reaches the console

Code in the output

Inside the output, console is a proxy that posts every call to the playground. So these calls do not appear in the browser's own DevTools console for the output frame. Experimental console._original keeps the native console.

Errors are logged for you: an unhandled promise rejection as console.error('Unhandled rejection', reason), and an uncaught error of the window as console.error(<stack>), with the out.rtcode.* URLs stripped from the stack, or with the message when there is no stack.

Workers

The console calls of <script type=worker> code, which runs in the output's service worker, arrive with πŸ›ŽοΈβš™οΈ as their first argument. The prefix is left out for console.group*() calls and for messages whose first argument contains %c. The calls are relayed to the output window of the session, so they do not reach the service worker's own DevTools console, and when no output window of the session is open, they are dropped.

A failure of a worker handler is logged with console.error, πŸ›ŽοΈβš™οΈ, a ☁️ marker for a worker that fails closed or β›… for one that fails open, a newline and the filtered stack. Throw Error objects in workers, so that a failure has a stack to log. The frames of the stack read <service-worker>:line:col. Their line numbers are not the editor's line numbers: treat them as approximate. See Using workers.

Several outputs

With several outputs open, in tabs or popups, every output's console calls land in the same console and badges. Your code runs once per output, so its logs repeat once per output. See Output windows.

Reloads clear everything

Every full output load, whether you press F5 or the output reloads for another reason, clears the console, the network list and the badges, and resets the fingerprint. During an Agent Folder Share, it also empties πŸ“œ.json. See Live sync and reloads.

Commands you type into the console

Note: Commands typed into the console run in the console page, on co.rtcode.io, not in the output. To evaluate code in the output, use o.eval.js during an Agent Folder Share, or the output's own code.

The network panel

The Network panel lists one row for each request that passes through the output's service worker: the method, the URL, the request headers and the start time, and then the status and the response headers. The size comes from Content-Length, and bodies are not shown. Each request adds 1 to the network badge.

Some requests do not appear: the load of the output's own root page, internal requests of the playground, and requests that bypass the service worker, such as the files of the RTCode.io runtime itself.

Keys in the console

Keys you press while the focus is in the console panel are handled by the console page. It forwards some of them to the playground: Ctrl with any key except A, C and V, any combination with Alt, and F4, F6, F9 and F12. So F12 closes the panel, F9 switches to the Network panel, or closes it when it is showing, and Ctrl+Alt+F runs Freeze All Windows. F5 and a lone Ctrl are swallowed: F5 does nothing while the focus is in the console.

The forwarded keys carry Ctrl and Alt only. Shift and ⌘ are dropped, so a shortcut that needs them reaches the playground without them. Move the focus back to the editor for those shortcuts, and on macOS prefer the βŒƒ-based forms from the console.

The console fingerprint

Experimental The console fingerprint turns everything the console receives into one hash. Two runs that log the same things in the same order have the same hash, so you can compare runs without reading them.

Note: The fingerprint is experimental and may change.

The panel

A small panel at the top right of the console holds a Fingerprint checkbox, with the tooltip "Press F5 to reload!", and a field with the current hash, with the tooltip "Alt + Click: copy console to clipboard". The field is cut off at 36% of the width of the viewport, and you can select its full text. The fingerprint is off by default and is not saved: reloading the playground resets everything and unchecks the box.

How the hash is built

The hash is a rolling SHA-256 chain. The state starts empty. For each console event while the box is checked, the new state is the SHA-256 of the previous state followed by the event: its method, its group depth and its data. The field shows the state as 64 lowercase hex digits. The data of an event depends on its method:

log, info, warn, error, debug, dir, dirxml, table, group, groupCollapsed, exceptions and failed assertions

The arguments.

trace

The arguments and the stack.

count

The label and the value.

countReset, time, timeStamp, profile, profileEnd

The label.

timeLog and timeEnd

The label and the duration in milliseconds, and for timeLog the arguments too.

groupEnd

Nothing.

Comparing two runs

Check Fingerprint, then press F5 with the focus in the editor or in the output. F5 inside the console is swallowed. Read the hash once the run has settled. Equal hashes mean identical console streams. console.clear(), whether your code calls it or every full output load does, resets the hash and the history.

html
<script type=module>
  const items = ['alpha', 'beta', 'gamma'];
  console.log('items', items.length);
  console.table(items.map((name, i) => ({ i, name })));
  console.assert(items.length === 3, 'three items');
</script>
  1. Open the console with F12 and check Fingerprint.
  2. Press F5 with the focus in the editor, and note the hash.
  3. Change the code, press F5 again and compare the hashes.

Deterministic calls give identical hashes. Avoid console.time(), console.timeEnd() and console.trace() when you compare runs: their durations and stacks differ from run to run, and they change the hash.

History and copying

The console records every call since it loaded or was last cleared, also while the box is unchecked, as an object with the method, the group depth and the arguments, the label, the value, the duration or the stack. Alt + click on the hash, while the box is checked, copies the hash, a blank line, and then one JSON object per line, without timestamps. The copy uses the clipboard permission that the console frame is granted.

The history can contain calls from before you checked the box, which the hash does not cover. So a copied hash and its log can disagree.

The same console in the agent folder

During an Agent Folder Share, the playground appends every relayed console call to πŸ“œ.json in the shared folder, so an agent can read what you see in the console. See Agent files.

The file

  • One line per call, as JSON Lines: {"<method>": [arguments]}. Any console function is relayed, and a call is recorded as it was made, so console.assert(true, 'x') gives {"assert":[true,"x"]}.
  • While a share is active, the live log is in πŸ“œ.json.crswap, because Chromium buffers a stream that is open for writing there. πŸ“œ.json stays empty until the share ends. Read both: cat πŸ“œ.json*.
  • Code in the output, including o.eval.js, produces unprefixed lines. Worker code produces lines with "πŸ›ŽοΈβš™οΈ" as the first element, for example {"log":["πŸ›ŽοΈβš™οΈ","hi"]}. The console calls of io.eval.js run in the playground window, and never reach the file.
  • Output errors are logged automatically: an uncaught error as {"error":["<filtered stack>"]}, and an unhandled rejection as {"error":["Unhandled rejection", <reason>]}.
  • console.clear() in the output, and clearing the console panel, empty the file. The file has no rotation and no size cap: it grows until it is cleared, the share starts again or the output reloads.

Note: The file records what your code logs, as plain text. Do not log secrets.

How arguments are recorded

The playground structured-clones the arguments and encodes them as JSON:

ArgumentRecorded as
A string, number, Boolean or nullItself
undefined, NaN and Β±Infinitynull
A DateAn ISO string
A Map, a Set or an Error object{}. Log e.stack or String(e) instead.

If an argument cannot be cloned, such as a function, a DOM node or a symbol, the whole array of arguments is recorded as one JSON string. So the value of a line is either an array or a string that you parse again.

js
const lines = text.split('\n').filter(Boolean).map(l => Object.entries(JSON.parse(l))[0]).map(([method, a]) => ({ method, worker: (typeof a === 'string' ? JSON.parse(a) : a)[0] === 'πŸ›ŽοΈβš™οΈ', args: typeof a === 'string' ? JSON.parse(a) : a }))

Browser requirements

Copying the fingerprint history needs the Clipboard API. The Agent Folder Share needs a Chromium-based browser on a desktop: see Agent Folder Share and Browser support.

See also