Corona SDK Pro Tip of the Day #22
Remote console

Send print output and runtime errors from a device via network to your computer for debugging.

When you are using the Simulator it's easy to see all the error messages and print output in it's console. However on a device we have to use either Xcode Organizer for iOS or adb logcat for Android.

Fear no more! Here comes remote console script that allows you to receive all the info you need directly from your device with no hassle.

Here is the function that does the magic, again from my app.lua.

local _M = {}

function _M.enableRemoteConsole(hostname, port)  
    if not hostname then
        error('Hostname is required', 2)
    end
    port = port or 22000
    local udp = require('socket').udp()
    udp:setsockname('*', port + 1)
    udp:settimeout(1)
    _G.print = function(...)
        local t = {...}
        local s = ''
        for i = 1, #t do
            local v = t[i]
            if v == nil then v = 'nil' end
            s = s .. tostring(v) .. '\t'
        end
        udp:sendto(s .. '\n', hostname, port)
    end
    Runtime:addEventListener('unhandledError', function(event)
        local message = 'Runtime error\n' .. event.errorMessage .. event.stackTrace .. '\n'
        udp:sendto(message, hostname, port)
    end)
end

return _M  

Use it like this:

app.enableRemoteConsole('192.168.0.15')  
print('Application Started')  

Now let's look what it does. First of all it accepts hostname and port. The latter is optional and has default value of 22000. Why 22000? Because it must be over 1024 and it's Pro Tip of the Day #22.

Then it requires socket library and sets up UDP networking. Why UDP and not TCP? Because UDP is connectionless, you can restart your app on your device without worrying about lost connections.

It assigns port number port + 1 so it won't conflict in the Simulator (so it works on devices and simulator), because it's a single computer and both sending and listening sockets will conflict.

Then it overrides built-in print() function. Whenever your app prints something, it goes directly into this function. Three dots ... show that this function accepts variable number of arguments. In a loop it constructs a string out of the table of arguments local t = {...}. We could use table.concat(t, '\t'), but it doesn't support nil values.

After that it sets a custom listener for the unhandledError event, this event is occurring for every runtime error we get. More info on that here. This listener just sends the error message over the network just like the print() function.

'192.168.0.15' happens to be my computer local IP address. Yours will be different (most likely).

Now we need something that we can listen with. In the Unix universe there is a nifty nc command, NC stands for "Network Cat," cat is another common Unix command for output.

nc is built-in for Mac and for Windows you can get it with cygwin.

Start up a terminal and write:

nc -luk 192.168.0.15 22000  

That will start a listener for UDP packets on port 22000. Don't forget to change IP address to yours. -luk options are Listen, Udp, Keep connection.

Once it's started and your app is running with app.enableRemoteConsole() you will be able to see all the messages that you usually see in the Simulator.

Indie Game Developer