When the runtime calls throw() for unrecoverable errors, it would be nice if there was a way to register a finalizer function to be called that would allow capturing the error in something other than stdout/stderr. This would differ from recover() in that it would still raise the error.
I'm using a web service in Go, it processes requests using goroutines. In one step, a key may be added to a map (e.g. map[string]string). In about 1 in a billion requests, under high request volume, the following fatal error is raised:
fatal error: concurrent map writes
We use an error logging library that "catches" panic() and stores the errors for tracking. I wanted to see this error be captured by that logging library. Since this error uses throw(), it cannot be handled by recover().
The text was updated successfully, but these errors were encountered:
It might be workable, but it seems outside the desired pattern. It would be extremely useful to be able to capture a stacktrace or other info and emit it somewhere else. The "how" here is outside my wheelhouse, but things like registering a function or interface implementation sound useful. It does seem unfortunate if the only way to catch this is to emit it to a file descriptor and let an outside, sidecar process pickup the error. Ideally, the runtime can emit it without needing an external process as that starts to complicate deployment.
I don't think that calling a function or method after throw is feasible. That implies running arbitrary Go code in a broken state: it will sometimes work and sometimes crash even worse with even less information. Maybe there is something we can do here, but it's not that.
It achieves the goal in a pretty heavy way: it makes the program relaunch itself in a child process so that the child process can panic and the parent process can (using heuristics monitoring stderr) react to the panic by e.g. writing it to a log file. Despite the claims in the readme, it unfortunately is inevitably a bit of a leaky abstraction due to its need to intermediate stderr and watch for the panic messages. For example, it forces stderr to appear as a pipe and therefore isatty returns false even if the parent process is copying stderr data to a tty.
I mention this here both in case it might be useful to someone who has this problem today but also in case it inspires ideas about what built-in features might make this approach more robust. For example, I wonder about a mechanism to ask the runtime to send panic information to somewhere other than stderr (e.g. to some other file descriptor) so that a monitoring program like this could do its work without interfering with the standard IO handles, although I think that design would be awkward on Windows where child processes cannot inherit nonstandard filehandles.
I know this isn't an easy problem to solve, so I appreciate the effort here.
With common deployments today living in containerized environments, outside of some sort of structured logging capture / parsing, gathering crash data like stack trace in a central location is extremely helpful. External processes and sidecars are not ideal. I didn't know if there could be a built-in struct type that could be defined and registered to be used when throw() is called. It could have a method that wouldn't allocate anything when called and could ship the stacktrace.
In Go it takes a runtime expert to write "a method that wouldn't allocate anything." We are not going to add any functionality to the language or standard library that can only be used safely if people are able to correctly restrict themselves to such a subset of the language. I encourage you to think of other approaches, because that one is not going to be adopted. Thanks.