Refactors for memory consumption

This reduces allocations along two critical paths:

1. The topics and instance ID for a source is computed when the struct is initialised, and not for each published line.
2. A file tail no longer creates a new buffer on each read attempt, but uses a shared buffer across reads/file rotations.

It also fixes a few memory and goroutine leaks and adds a few sanity tests.