Passing around a pointer to a log, unsuccessfully

Hello All,

I am trying to create a custom log file library, a simple extension of log.Logger.

Using the following library:

package customlog

import (
	"log"
	"os"
)

// CustomLog provides an override log.Logger object
type CustomLog struct {
	Custom *log.Logger
}

// New creates a new CustoLog - arg is true when logging
// to the CLI, false to log to file
func New(console bool) (*CustomLog, error) {
	c := new(CustomLog)

	if console {
		c.Custom = log.New(os.Stdout, "v6: ", log.Lshortfile|log.LstdFlags)
	} else {
		// errorlog, err := os.OpenFile("v6.log", os.O_RDWR|os.O_CREATE|os.O_APPEND|os.O_TRUNC, 0666)
		errorlog, err := os.OpenFile("v6.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			return c, err
		}
		c.Custom = log.New(errorlog, "v6: ", log.Lshortfile|log.LstdFlags)
		defer errorlog.Close()
	}
	c.Custom.Println("Creating log file.")

	return c, nil
}

The outgoing log.Custom.Println() in main() does not append any text to the file:

package main

import (
	"fmt"
	"os"

	"/.../customlog"
)

func main() {

	log, err := customlog.New(false)
	if err != nil {
		fmt.Printf("error = %v\n", err)
		log.Custom.Printf("error creating custom log: %v", err)
		os.Exit(1)
	}

	log.Custom.Println("System fully loaded. Scramble the jets.")

}

I thought by returning a pointer to the object the caller should obtain write access? This is (or will be) part of a much larger existing application and returns no building or vetting errors or warnings. What am I missing? The console option works just fine.

Thanks,

JB

I guess the problem is defer errorlog.Close() within New(). The deferred function call runs when the surrounding function exits, so after calling New(false), the file is already closed.

2 Likes

Wow. I hadn’t thought of that. It explains why it worked in the previous, monolithic version of this application and not in the current package-based layout. Thanks, I will drop that defer when I get back to the code tomorrow night and see how it behaves. Easy enough to put in a hook to close the file when the application exits.

Odd that I don’t see a run-time error, though, trying to write to a closed file?

Thanks again.

JB

I, too, was puzzled by this until I remembered that the Print functions do return error values. It is just that no one takes care of reading them…

Yes, there is that. I will start checking the return value for those log calls. Thanks!

Yes removing the deferred call to close seems to have done the trick. Also, for anyone curious, one library I use needs to be able to write to the same log created in main(). I solved this by making a pointer to a log object part of the library, and setting it up with a New() function:

type Request struct {
	details   reqDetail
	reqLogger *log.Logger
}


func New(clog *log.Logger) (*Request, error) {
	req := new(Request)
	req.reqLogger = clog

	return req, nil
}

Then, call from main():

	logger, err := customlog.New(false)
	if err != nil {
		fmt.Printf("error = %v\n", err)
		os.Exit(1) // should panic and notify
	}

    // ....

	request, err := requests.New(logger.Custom)

Seems to work well, and will allow me to pass around the logger pointer for “write” HTTP handlers that can’t gracefully return an error status to main().

Seems legit - comments?

JB

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