Skip to content

Commit f742f24

Browse files
authored
Allow setting a different output stream than os.Stderr for std.trace (google#514)
Allow std.trace output to other streams
1 parent 4a3144a commit f742f24

File tree

4 files changed

+50
-16
lines changed

4 files changed

+50
-16
lines changed

builtins.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
"encoding/json"
2525
"fmt"
2626
"math"
27-
"os"
2827
"reflect"
2928
"sort"
3029
"strconv"
@@ -248,10 +247,10 @@ func builtinTrace(i *interpreter, x value, y value) (value, error) {
248247
return nil, err
249248
}
250249
trace := i.stack.currentTrace
251-
filename := trace.loc.FileName
250+
filename := trace.loc.File.DiagnosticFileName
252251
line := trace.loc.Begin.Line
253252
fmt.Fprintf(
254-
os.Stderr, "TRACE: %s:%d %s\n", filename, line, xStr.getGoString())
253+
i.traceOut, "TRACE: %s:%d %s\n", filename, line, xStr.getGoString())
255254
return y, nil
256255
}
257256

interpreter.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package jsonnet
1919
import (
2020
"bytes"
2121
"fmt"
22+
"io"
2223
"math"
2324
"reflect"
2425
"sort"
@@ -257,6 +258,9 @@ type interpreter struct {
257258

258259
// Keeps imports
259260
importCache *importCache
261+
262+
// Output stream for trace() for
263+
traceOut io.Writer
260264
}
261265

262266
// Map union, b takes precedence when keys collide.
@@ -1215,10 +1219,11 @@ func buildObject(hide ast.ObjectFieldHide, fields map[string]value) *valueObject
12151219
return makeValueSimpleObject(bindingFrame{}, fieldMap, nil, nil)
12161220
}
12171221

1218-
func buildInterpreter(ext vmExtMap, nativeFuncs map[string]*NativeFunction, maxStack int, ic *importCache) (*interpreter, error) {
1222+
func buildInterpreter(ext vmExtMap, nativeFuncs map[string]*NativeFunction, maxStack int, ic *importCache, traceOut io.Writer) (*interpreter, error) {
12191223
i := interpreter{
12201224
stack: makeCallStack(maxStack),
12211225
importCache: ic,
1226+
traceOut: traceOut,
12221227
nativeFuncs: nativeFuncs,
12231228
}
12241229

@@ -1288,9 +1293,9 @@ func evaluateAux(i *interpreter, node ast.Node, tla vmExtMap) (value, error) {
12881293

12891294
// TODO(sbarzowski) this function takes far too many arguments - build interpreter in vm instead
12901295
func evaluate(node ast.Node, ext vmExtMap, tla vmExtMap, nativeFuncs map[string]*NativeFunction,
1291-
maxStack int, ic *importCache, stringOutputMode bool) (string, error) {
1296+
maxStack int, ic *importCache, traceOut io.Writer, stringOutputMode bool) (string, error) {
12921297

1293-
i, err := buildInterpreter(ext, nativeFuncs, maxStack, ic)
1298+
i, err := buildInterpreter(ext, nativeFuncs, maxStack, ic, traceOut)
12941299
if err != nil {
12951300
return "", err
12961301
}
@@ -1317,9 +1322,9 @@ func evaluate(node ast.Node, ext vmExtMap, tla vmExtMap, nativeFuncs map[string]
13171322

13181323
// TODO(sbarzowski) this function takes far too many arguments - build interpreter in vm instead
13191324
func evaluateMulti(node ast.Node, ext vmExtMap, tla vmExtMap, nativeFuncs map[string]*NativeFunction,
1320-
maxStack int, ic *importCache, stringOutputMode bool) (map[string]string, error) {
1325+
maxStack int, ic *importCache, traceOut io.Writer, stringOutputMode bool) (map[string]string, error) {
13211326

1322-
i, err := buildInterpreter(ext, nativeFuncs, maxStack, ic)
1327+
i, err := buildInterpreter(ext, nativeFuncs, maxStack, ic, traceOut)
13231328
if err != nil {
13241329
return nil, err
13251330
}
@@ -1337,9 +1342,9 @@ func evaluateMulti(node ast.Node, ext vmExtMap, tla vmExtMap, nativeFuncs map[st
13371342

13381343
// TODO(sbarzowski) this function takes far too many arguments - build interpreter in vm instead
13391344
func evaluateStream(node ast.Node, ext vmExtMap, tla vmExtMap, nativeFuncs map[string]*NativeFunction,
1340-
maxStack int, ic *importCache) ([]string, error) {
1345+
maxStack int, ic *importCache, traceOut io.Writer) ([]string, error) {
13411346

1342-
i, err := buildInterpreter(ext, nativeFuncs, maxStack, ic)
1347+
i, err := buildInterpreter(ext, nativeFuncs, maxStack, ic, traceOut)
13431348
if err != nil {
13441349
return nil, err
13451350
}

jsonnet_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package jsonnet
33
import (
44
"bytes"
55
"encoding/json"
6+
"fmt"
67
"reflect"
78
"strings"
89
"testing"
@@ -327,3 +328,24 @@ func TestTLATypes(t *testing.T) {
327328
}
328329
assertVarOutput(t, jsonStr)
329330
}
331+
332+
func TestSetTraceOut(t *testing.T) {
333+
traceOut := &strings.Builder{}
334+
vm := MakeVM()
335+
vm.SetTraceOut(traceOut)
336+
337+
const filename = "blah.jsonnet"
338+
const msg = "TestSetTraceOut Trace Message"
339+
expected := fmt.Sprintf("TRACE: %s:1 %s", filename, msg)
340+
input := fmt.Sprintf("std.trace('%s', 'rest')", msg)
341+
342+
_, err := vm.EvaluateAnonymousSnippet(filename, input)
343+
if err != nil {
344+
t.Errorf("Unexpected error: %v", err)
345+
}
346+
347+
actual := removeExcessiveWhitespace(traceOut.String())
348+
if actual != expected {
349+
t.Errorf("Expected %q, but got %q", expected, actual)
350+
}
351+
}

vm.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package jsonnet
1919
import (
2020
"errors"
2121
"fmt"
22+
"io"
2223
"os"
2324
"path/filepath"
2425
"runtime/debug"
@@ -44,6 +45,7 @@ type VM struct {
4445
ErrorFormatter ErrorFormatter
4546
StringOutput bool
4647
importCache *importCache
48+
traceOut io.Writer
4749
}
4850

4951
// extKind indicates the kind of external variable that is being initialized for the VM
@@ -78,6 +80,7 @@ func MakeVM() *VM {
7880
ErrorFormatter: &termErrorFormatter{pretty: false, maxStackTraceSize: 20},
7981
importer: &FileImporter{},
8082
importCache: makeImportCache(defaultImporter),
83+
traceOut: os.Stderr,
8184
}
8285
}
8386

@@ -93,6 +96,11 @@ func (vm *VM) flushValueCache() {
9396
vm.importCache.flushValueCache()
9497
}
9598

99+
// SetTraceOut sets the output stream for the builtin function std.trace().
100+
func (vm *VM) SetTraceOut(traceOut io.Writer) {
101+
vm.traceOut = traceOut
102+
}
103+
96104
// ExtVar binds a Jsonnet external var to the given value.
97105
func (vm *VM) ExtVar(key string, val string) {
98106
vm.ext[key] = vmExt{value: val, kind: extKindVar}
@@ -174,7 +182,7 @@ func (vm *VM) Evaluate(node ast.Node) (val string, err error) {
174182
err = fmt.Errorf("(CRASH) %v\n%s", r, debug.Stack())
175183
}
176184
}()
177-
return evaluate(node, vm.ext, vm.tla, vm.nativeFuncs, vm.MaxStack, vm.importCache, vm.StringOutput)
185+
return evaluate(node, vm.ext, vm.tla, vm.nativeFuncs, vm.MaxStack, vm.importCache, vm.traceOut, vm.StringOutput)
178186
}
179187

180188
// EvaluateStream evaluates a Jsonnet program given by an Abstract Syntax Tree
@@ -185,7 +193,7 @@ func (vm *VM) EvaluateStream(node ast.Node) (output []string, err error) {
185193
err = fmt.Errorf("(CRASH) %v\n%s", r, debug.Stack())
186194
}
187195
}()
188-
return evaluateStream(node, vm.ext, vm.tla, vm.nativeFuncs, vm.MaxStack, vm.importCache)
196+
return evaluateStream(node, vm.ext, vm.tla, vm.nativeFuncs, vm.MaxStack, vm.importCache, vm.traceOut)
189197
}
190198

191199
// EvaluateMulti evaluates a Jsonnet program given by an Abstract Syntax Tree
@@ -197,7 +205,7 @@ func (vm *VM) EvaluateMulti(node ast.Node) (output map[string]string, err error)
197205
err = fmt.Errorf("(CRASH) %v\n%s", r, debug.Stack())
198206
}
199207
}()
200-
return evaluateMulti(node, vm.ext, vm.tla, vm.nativeFuncs, vm.MaxStack, vm.importCache, vm.StringOutput)
208+
return evaluateMulti(node, vm.ext, vm.tla, vm.nativeFuncs, vm.MaxStack, vm.importCache, vm.traceOut, vm.StringOutput)
201209
}
202210

203211
func (vm *VM) evaluateSnippet(diagnosticFileName ast.DiagnosticFileName, filename string, snippet string, kind evalKind) (output interface{}, err error) {
@@ -212,11 +220,11 @@ func (vm *VM) evaluateSnippet(diagnosticFileName ast.DiagnosticFileName, filenam
212220
}
213221
switch kind {
214222
case evalKindRegular:
215-
output, err = evaluate(node, vm.ext, vm.tla, vm.nativeFuncs, vm.MaxStack, vm.importCache, vm.StringOutput)
223+
output, err = evaluate(node, vm.ext, vm.tla, vm.nativeFuncs, vm.MaxStack, vm.importCache, vm.traceOut, vm.StringOutput)
216224
case evalKindMulti:
217-
output, err = evaluateMulti(node, vm.ext, vm.tla, vm.nativeFuncs, vm.MaxStack, vm.importCache, vm.StringOutput)
225+
output, err = evaluateMulti(node, vm.ext, vm.tla, vm.nativeFuncs, vm.MaxStack, vm.importCache, vm.traceOut, vm.StringOutput)
218226
case evalKindStream:
219-
output, err = evaluateStream(node, vm.ext, vm.tla, vm.nativeFuncs, vm.MaxStack, vm.importCache)
227+
output, err = evaluateStream(node, vm.ext, vm.tla, vm.nativeFuncs, vm.MaxStack, vm.importCache, vm.traceOut)
220228
}
221229
if err != nil {
222230
return "", err

0 commit comments

Comments
 (0)