mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 09:48:32 -05:00
main: Log about reliance on GODEBUG settings
The Go runtime provides a number of configuration knobs that subtly change its behavior, and we cannot control which of these is available over time as we change which version of Go we're building with. It's therefore possible that an OpenTofu user might be intentionally or unintentionally relying on one of these settings for OpenTofu to work on their system, in which case they would be broken if they upgraded to a newer version of OpenTofu which uses a different Go version that no longer supports that setting. These log lines are intended to help us more quickly notice that possibility if someone opens a bug report describing an unexpected behavior change after upgrading to a new OpenTofu minor release series. We can ask the reporter to share "TF_LOG=debug" output from both the previous and new releases to compare, and then these log lines should appear in the older version's output so we can search the Go codebase and issue tracker for each of the mentioned names to learn if the handling of that setting has changed between Go versions. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
This commit is contained in:
@@ -380,6 +380,12 @@ func realMain() int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We might generate some additional log lines if OpenTofu relied on any
|
||||||
|
// non-default Go runtime behaviors enabled by GODEBUG settings, because
|
||||||
|
// they might be relevant when trying to reproduce certain problems for
|
||||||
|
// debugging or bug reporting purposes.
|
||||||
|
logGodebugUsage()
|
||||||
|
|
||||||
// if we are exiting with a non-zero code, check if it was caused by any
|
// if we are exiting with a non-zero code, check if it was caused by any
|
||||||
// plugins crashing
|
// plugins crashing
|
||||||
if exitCode != 0 {
|
if exitCode != 0 {
|
||||||
|
|||||||
@@ -6,9 +6,62 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
|
"runtime/metrics"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/opentofu/opentofu/internal/logging"
|
||||||
"github.com/opentofu/opentofu/version"
|
"github.com/opentofu/opentofu/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Version = version.Version
|
var Version = version.Version
|
||||||
|
|
||||||
var VersionPrerelease = version.Prerelease
|
var VersionPrerelease = version.Prerelease
|
||||||
|
|
||||||
|
// logGodebugUsage produces extra DEBUG log lines if the Go runtime's metrics
|
||||||
|
// suggest that code that was run so far relied on any non-default "GODEBUG"
|
||||||
|
// settings, which could be helpful in reproducing a bug report if the
|
||||||
|
// behavior differs based on such a setting.
|
||||||
|
//
|
||||||
|
// For this to be useful it must be run just before we're about to exit, after
|
||||||
|
// we've already performed all of the requested work.
|
||||||
|
func logGodebugUsage() {
|
||||||
|
// These constants reflect the documented conventions from the
|
||||||
|
// runtime/metrics package, so we can filter for only the metrics that
|
||||||
|
// are relevant to this function.
|
||||||
|
const godebugMetricPrefix = "/godebug/non-default-behavior/"
|
||||||
|
const godebugMetricSuffix = ":events"
|
||||||
|
|
||||||
|
if !logging.IsDebugOrHigher() {
|
||||||
|
// No point in doing any of this work if the log lines are going to
|
||||||
|
// be filtered out anyway.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
metricDescs := metrics.All()
|
||||||
|
for _, metric := range metricDescs {
|
||||||
|
if !metric.Cumulative || metric.Kind != metrics.KindUint64 {
|
||||||
|
// godebug counters are always cumulative uint64, so this quickly
|
||||||
|
// filters some irrelevant metrics before we do any string
|
||||||
|
// comparisons.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(metric.Name, godebugMetricPrefix) {
|
||||||
|
continue // irrelevant metric
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(metric.Name, godebugMetricSuffix) {
|
||||||
|
continue // irrelevant metric
|
||||||
|
}
|
||||||
|
// The metrics API is designed for applications that want to periodically
|
||||||
|
// re-extract the same set of metrics in a long-running application by
|
||||||
|
// reusing a preallocated buffer, but we don't have that need here and so
|
||||||
|
// we'll just read one metric at a time into a single-element array.
|
||||||
|
var samples [1]metrics.Sample
|
||||||
|
samples[0].Name = metric.Name
|
||||||
|
metrics.Read(samples[:])
|
||||||
|
if count := samples[0].Value.Uint64(); count != 0 {
|
||||||
|
name := metric.Name[len(godebugMetricPrefix) : len(metric.Name)-len(godebugMetricSuffix)]
|
||||||
|
log.Printf("[DEBUG] Relied on GODEBUG %q %d times during this execution; behavior might change in future OpenTofu versions", name, count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user