In recent years, since the arrival of D3.js, whenever there is a task involving charts or graph visualisation I tend to gravitate towards JavaScript libraries. This is mainly because D3.js provides an easy way to bring data to life using HTML, SVG, and CSS, with a data-driven approach. It’s easy to customise and integrate for your own use case, and there are plethora of beautiful interactive chart examples out there.
However, having experience in creating C++ Qt user interfaces, sometimes I miss a more native approach. There is something about compiled small-sized binary executables, or something without having to deal with different browser involvements. So as a side project, I thought it was time to explore something new, and go on an adventure to find an alternative.
Always be curious, have an adventure
Looking around within my work environment (something I’m familiar with) for inspiration, I decided that a suitable subject for this project would be a tool to visualise operations in MongoDB log files. The tool would use a scatter plot to map out log entries based on the timestamp and duration of the operation.
Example of MongoDB log entry (v3.4.9):
2017-11-13T10:22:19.039+1100 I COMMAND [conn3] command charts.golang appName: "MongoDB Shell" command: find { find: "golang", filter: { a: { $regex: /^d.*/ } } } planSummary: COLLSCAN keysExamined:0 docsExamined:1000 cursorExhausted:1 numYields:7 nreturned:42 reslen:2638 locks:{ Global: { acquireCount: { r: 16 } }, Database: { acquireCount: { r: 8 } }, Collection: { acquireCount: { r: 8 } } } protocol:op_command 1ms
As a newbie in the Golang programming language, this would also be a perfect opportunity to increase my fluency in the language. Because you know what they say: if you don’t use it, you lose it. With those decisions made, it was now time to look for suitable Golang dependencies.
Keep Looking
There were (probably) two libraries needed to start the project: a library to render scatter plots and a library to parse MongoDB log files.
Generally, the Golang plotting libraries that I know just generate static, albeit beautiful, images; to name a couple:
At this point I decided to go down the path of writing my own custom interactive widget. After a quick search I found golang-ui/nuklear. It’s a package that provides Go bindings for a small ANSI C GUI library. See also the related github.com/vurtun/nuklear.
One of the examples of GUI from the Github repo.
Nuklear has some desirable features that caught my eye:
First, I did a quick test to create entry plots:
c1 := nk.NkRect(float32(fx), float32(fy), 5.0, 5.0) nk.NkFillCircle(canvas, c1, nk.NkRgb(171, 239, 29))
if nk.NkInputHasMouseClickDownInRect(input, nk.ButtonLeft, c1, 1) > 0 {log.Println("Receive a click on coordinate: ", fx, fy)}
Full source code for the simple example above can be found on gist://test_scatter.go
The size of this binary executable was only ~5MB. Without any code optimisation I could render ~75,000 points before there’s a bit of lag.
With another quick search I found a Golang library to parse MongoDB log files, github.com/honeycombio/mongodbtools, written by honeycomb.io. With a few extra lines of Golang code, I could parse log files and plot them into the interactive widget:
The size of this binary executable was ~10MB.
At this point I could finish fixing up the X and Y axis information that was missing, scaling the input timestamp and the duration to fit within the size of the application window and calculate the marker points.
Another path that I explored was using one of the many Golang plotting libraries to generate an SVG or PNG image and render it as a texture/bitmap on the GL widget, refreshing the texture generation as new data arrives. I quickly tried implementing this path using github.com/wcharczuk/go-chart to generate the static image:
The challenge here was to map a mouse click received on the widget and correlate it back to an item on the texture/bitmap to find out which entry point was clicked.
Always learning…
Okay, so what did I learn from this little adventure:
Perhaps it’s useful to start a Golang library to render interactive graphs, perhaps there’s already one out there that I’m not aware of. Let me know what you think.