When Caplin announced a HTML5 Hackathon we formed a team of three and decided to use the new technologies in HTML5 to develop a background logger for one of Caplin’s flagship JavaScript libraries- StreamLink for Browsers (SL4B). SL4B provides an API to stream data from Caplin Xaqua server components to a web client, usually Caplin Trader.
by Lawrence Owusu, Neal Dangerfield & Aleksei Loktionov
The Issue of Logging
One of the major problems with JavaScript libraries is the issue of logging. Because the application is running in the browser, any logging has to be shown in the browser since the log messages cannot be written to a file or a disk on the client machine due to browser security restrictions.
Currently, when SL4B logging is turned on, the log messages are written into a new HTML window. This is memory and CPU intensive and hence it slows down the web application.
Secondly, the logging functionality cannot be accessed on demand – you either turn on the functionality when the application starts, or you never get any logging at all. The current manner of logging means that this functionality will be problematic for mobile devices and the log window cannot handle large amount of logs.
Our new architecture
We took a decision to use the HTML5 web database API to store the logs. We later improved this further by using the HTML5 web worker to do all database transactions.
The architecture of our project had a web worker class which sent commands to a utility class that actually performed the database transactions. In this utility class, we opened a web database synchronously if it was already created, however if it is the first time running the application, we created the database.
The utility class submitted transactions to the database synchronously because there were a number of issues/problems we faced when we tried running the utility to perform asynchronous transactions to the database (i.e. we used openDatabaseSync()
instead of the openDatabase()
method)
Issues & Solutions
The database contains only one table with two columns – the first one is the ID column which contains a unique ID of the log line. The next column, LOG, is a text column which stores the log lines. To reduce the number of transactions we perform, we batch the log lines (every 50 log lines) by concatenating them into one string and delimiting the log lines with the string “<msg>”. We then save the batched log lines into the database as one record.
When the web worker receives a log message, it sends the log message with an insert command to the utility class. The utility class then batches the log lines and then when the correct number of log lines are reached it inserts the batched log lines into the database as one record. Communication between the web worker and the utility class is done using the postMessage()
method.
If the web worker gets a request to fetch the logs, it sends a command to the utility class that goes into the database to retrieve the logs and then sends the retrieved logs lines back to the web worker, that then forwards it to the client.
Conclusion
We did some tests and realised that the performance of the web application does not seem to be affected adversely by using the web worker and web database. Amongst the challenges we faced was the fact that in the web worker, methods such as console.log()
or console.error()
do not work, so to log the activities of the worker itself, we have to post messages to the utility class and call these methods from there.