Recently at work, I ran into a problem where I needed to create a pass through binary - basically a program that takes the calling process' IO streams and connects them to a child process.

Since the IO streams are being used by the child process, we have to be careful to also setup a simple logger to capture information about the pass through program, since writing to or reading from standard streams could interfere with the child process.

If I end up having to use this at work, it will need to meet a few requirements:

  • zero dependency binary
  • small binary footprint
  • cross platform

At work, I've been writing a lot of Golang - so I figured it would be fun to compare both Go and Nim at this simple task, especially since they both meet all the requirements.

Here is the sample child process I'm calling - a really simple python script that just prints its IO:

Golang

I have a love/hate relationship with Go. It's so minimal... but it's so minimal. Setting up a simple logger ended up being the hardest part surprisingly.

Its kind of funny to see how much boiler plate there is for something as simple and basic as logging - I do know there are lots of libraries out there though.

This simple pass through comes in at about 2.2 MB.

❯ echo "foo" | ./go-entrypoint
Inside a python process!
Reading from stdin... (e.g. a chunk)
======================================================================
foo
======================================================================
Exiting now from python!

And the log:

❯ cat /tmp/go-entrypoint.log
go-entrypoint: main.go:63: Inside a go process!
go-entrypoint: main.go:67: Setting up: /opt/python/bin/python reflector.py
go-entrypoint: main.go:71: Starting External Process...
go-entrypoint: main.go:86: Exiting from golang...

Nim

For Nim, the logging situation is a lot simpler, but its a little harder to google for things (and part of what made me want to write this post). To setup the same thing, I found that the execCmd proc in the osproc module does exactly what I want:

This simple pass trhough comes in about 190KB.

❯ echo "bar" | ./entrypoint
Inside a python process!
Reading from stdin... (e.g. a chunk)
======================================================================
bar
======================================================================
Exiting now from python!

And the log:

❯ cat /tmp/nim-entrypoint.log
I, [2018-10-06T12:54:34] -- entrypoint: Inside a nim process!
I, [2018-10-06T12:54:34] -- entrypoint: Setting up: /opt/python/bin/python
reflector.py
I, [2018-10-06T12:54:34] -- entrypoint: Starting External Process...
I, [2018-10-06T12:54:34] -- entrypoint: Exiting from nim...

Postscript

Cover photo is from - https://www.flickr.com/photos/seattlemunicipalarchives/12504672623