gotk4 icon indicating copy to clipboard operation
gotk4 copied to clipboard

Custom glib.LogSetWriter

Open OmegaRogue opened this issue 2 years ago • 9 comments

I'm trying to use a custom log writer that uses zerolog, but I'm getting Error: GLib: g_log_set_writer_func() called multiple times because of this code in pkg/glib/v2/gmessages.go:

func init() {
	if os.Getenv("G_DEBUG") == "" {
		LogUseDefaultLogger() // see gotk4's gendata.go
	}
}

I agree with the note in gir/cmd/gir-generate/gendata/gendata.go that this is referring to

	// This one might be subjective, but I think most can agree that having a
	// library dumping stuff into the console isn't the best idea. Not only
	// would this make logging more consistently-looking, it would also allow
	// the user to blot out all logging using Go's stdlib log.
	//
	// Somewhere down the line, a user might complain that a gotk4 application
	// isn't obeying environment variables that GLib made up on its own. And
	// that's understandable. Pull requests can be made to improve the piece of
	// code written below, but consistency is still more ideal, I think.
	p.Line(`
		func init() {
			if os.Getenv("G_DEBUG") == "" {
				LogUseDefaultLogger() // see gotk4's gendata.go
			}
		}
	`)

but having that set in an ìnit` function with no way to disable it permanently from inside the application (even putting an init function in main.go that sets the variable doesn't work) isn't the best approach, as this effectively makes it impossible to use a custom logger afaik. Is there a way around this currently that I'm not seeing or does this need improvement?

OmegaRogue avatar Mar 21 '23 18:03 OmegaRogue

This likely needs improvements, but init()s behave weirdly. I'm not sure how to allow this; maybe I should move this to outside init(). I'm not sure where though, maybe gtk_init()?

diamondburned avatar Mar 21 '23 19:03 diamondburned

I think that makes sense, as gtk_init() should be called before any GTK API is used

OmegaRogue avatar Mar 21 '23 20:03 OmegaRogue

Right, it should work. However, there are other ways to initialize GTK without calling Go's gtk.Init() function, e.g. by doing gtk.NewApplication or by calling adw.Init().

diamondburned avatar Mar 21 '23 21:03 diamondburned

Maybe using an internal variable that checks if the logger has been added before and then adding it in all of those if it hasnt already been added?

OmegaRogue avatar Mar 21 '23 21:03 OmegaRogue

That could work, but init()'s ordering is pretty much undefined. It would be hacky to inject a logger beforehand, but it could look something like:

var _ = glib.DontInjectLogger()

diamondburned avatar Mar 21 '23 21:03 diamondburned

I was more thinking of

var logWriterAdded = false

And then inside the body of LogSetWriter

if logWriterAdded {
  return
}
logWriterAdded = true
// Rest of the body
}

And then putting the function that sets the default logger at the starz of every method that allows starting the gtk application, but that would also work

OmegaRogue avatar Mar 21 '23 21:03 OmegaRogue

And then putting the function that sets the default logger at the starz of every method that allows starting the gtk application

This is hard if not impossible to figure out. You can try and guess it, but other C libraries (e.g. libadwaita) may call the C function on its own and bypass the Go call anyway.

Another method could just be introducing our own callback that the user can swap out manually in their main().

diamondburned avatar Mar 22 '23 02:03 diamondburned

Both of those should be good, the first one would probably be the simplest to handle ig

OmegaRogue avatar Mar 22 '23 03:03 OmegaRogue