Files
releases/v1/debug/trace.go
T
Anders Eknert bd5ceb5142 Enable unused-receiver linter (revive) (#7448)
Signed-off-by: Anders Eknert <anders@styra.com>
2025-03-14 11:41:25 +01:00

110 lines
2.1 KiB
Go

// Copyright 2024 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package debug
import (
"github.com/open-policy-agent/opa/v1/rego"
"github.com/open-policy-agent/opa/v1/topdown"
)
type stack interface {
topdown.QueryTracer
Current() (int, *topdown.Event)
Event(i int) *topdown.Event
Next() (int, *topdown.Event)
Result() rego.ResultSet
Close() error
}
type debugTracer struct {
history []*topdown.Event
eventChan chan *topdown.Event
waitChan chan bool
enabled bool
resultSet rego.ResultSet
}
func newDebugTracer() *debugTracer {
return &debugTracer{
eventChan: make(chan *topdown.Event),
waitChan: make(chan bool),
enabled: true,
}
}
func (dt *debugTracer) Enabled() bool {
return dt.enabled
}
func (dt *debugTracer) TraceEvent(e topdown.Event) {
if !dt.enabled {
return
}
defer func() {
if recover() != nil {
dt.enabled = false
}
}()
dt.eventChan <- &e
// Block until the consumer wants another event, so that evaluation isn't "ahead"
<-dt.waitChan
}
func (*debugTracer) Config() topdown.TraceConfig {
return topdown.TraceConfig{
PlugLocalVars: true,
}
}
func (dt *debugTracer) Current() (int, *topdown.Event) {
stackLength := len(dt.history)
if stackLength > 0 {
return stackLength - 1, dt.history[len(dt.history)-1]
}
return -1, nil
}
func (dt *debugTracer) Event(i int) *topdown.Event {
if i >= 0 && i < len(dt.history) {
return dt.history[i]
}
return nil
}
func (dt *debugTracer) Next() (int, *topdown.Event) {
if !dt.enabled {
return -1, nil
}
if len(dt.history) > 0 {
// We don't need to unblock the producer for the first event.
dt.waitChan <- true
}
e, ok := <-dt.eventChan
if ok {
dt.history = append(dt.history, e)
return len(dt.history) - 1, e
}
return len(dt.history) - 1, nil
}
func (dt *debugTracer) Result() rego.ResultSet {
return dt.resultSet
}
func (dt *debugTracer) Close() error {
if !dt.enabled {
return nil
}
dt.enabled = false
close(dt.eventChan)
close(dt.waitChan)
return nil
}