Execute Goroutine with piped os.Stdout/os.Stderr output?

In some languages, usually scripting but some compiled ones, it’s possible to execute code whilst piping all subsequent output to a custom stream.

I’m creating a piece of software that will run completely unattended and am currently replacing the global Stdout/Stderr streams with one that I can access remotely and persistently, however I would like to divide these up. Because of how I’ve got logging configured, there’s a very simple way to do that, since loggers are created using a factory method. Example:

var debug, info, warn, critical = logging.NewLoggers("modules.gnr")

I could simply make this factory method write to a specific stream according to the provided logger namespace, but there’s an extra little detail, and that is… I’m also using Cron(-ish) jobs, and I would like each execution of the job to have it’s own log. Since the loggers are created on a package-level basis, I can’t see how I would go about doing this without passing these level-logger values around (which sounds like hell)

I had the idea of using Context (with a pointer to the relevant logger), and passing the Context around, but I really don’t want to. Is there a different, not-totally-disgusting way to do this?

Would appreciate any help. I wouldn’t say I’m new to Go, but this is by far the biggest project I’ve done in it.

This sample using piping of Stdout/Stderr might help.

You could make the loggers globally available in each package and create the loggers in the init() function which is run before main.

package somepackage

import (

// Variables are global in package
var debug, info, warn, critical logging.Logger

// initalize the loggers
func init() {
    debug, info, warn, critical = logging.NewLoggers("somepackage")

// use them in function
func someFunc()  {
    user, err := CurrentUser()
    if err != nil {
         critical.Log("Current user not found")
    } else {
        info.Logf("Current user is %s", user)

This is effectively what I was doing. Issue is I needed it to be “instance specific”. I ended up using context anyway, and making a single custom Logger abstraction that has Info/Infof, Warn/Warnf, etc. Then a helper method:
log := logger.GetLoggers(context)

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.