Source file src/internal/trace/testtrace/helpers.go

     1  // Copyright 2025 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package testtrace
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"internal/testenv"
    11  	"internal/trace/raw"
    12  	"internal/trace/version"
    13  	"io"
    14  	"os"
    15  	"strings"
    16  	"testing"
    17  )
    18  
    19  // MustHaveSyscallEvents skips the current test if the current
    20  // platform does not support true system call events.
    21  func Dump(t *testing.T, testName string, traceBytes []byte, forceToFile bool) {
    22  	onBuilder := testenv.Builder() != ""
    23  	onOldBuilder := !strings.Contains(testenv.Builder(), "gotip") && !strings.Contains(testenv.Builder(), "go1")
    24  
    25  	if onBuilder && !forceToFile {
    26  		// Dump directly to the test log on the builder, since this
    27  		// data is critical for debugging and this is the only way
    28  		// we can currently make sure it's retained.
    29  		s := dumpTraceToText(t, traceBytes)
    30  		if onOldBuilder && len(s) > 1<<20+512<<10 {
    31  			// The old build infrastructure truncates logs at ~2 MiB.
    32  			// Let's assume we're the only failure and give ourselves
    33  			// up to 1.5 MiB to dump the trace.
    34  			//
    35  			// TODO(mknyszek): Remove this when we've migrated off of
    36  			// the old infrastructure.
    37  			t.Logf("text trace too large to dump (%d bytes)", len(s))
    38  		} else {
    39  			t.Log(s)
    40  		}
    41  	} else {
    42  		// We asked to dump the trace or failed. Write the trace to a file.
    43  		t.Logf("wrote trace to file: %s", dumpTraceToFile(t, testName, traceBytes))
    44  	}
    45  }
    46  
    47  func dumpTraceToText(t *testing.T, b []byte) string {
    48  	t.Helper()
    49  
    50  	br, err := raw.NewReader(bytes.NewReader(b))
    51  	if err != nil {
    52  		t.Fatalf("dumping trace: %v", err)
    53  	}
    54  	var sb strings.Builder
    55  	tw, err := raw.NewTextWriter(&sb, version.Current)
    56  	if err != nil {
    57  		t.Fatalf("dumping trace: %v", err)
    58  	}
    59  	for {
    60  		ev, err := br.ReadEvent()
    61  		if err == io.EOF {
    62  			break
    63  		}
    64  		if err != nil {
    65  			t.Fatalf("dumping trace: %v", err)
    66  		}
    67  		if err := tw.WriteEvent(ev); err != nil {
    68  			t.Fatalf("dumping trace: %v", err)
    69  		}
    70  	}
    71  	return sb.String()
    72  }
    73  
    74  func dumpTraceToFile(t *testing.T, testName string, b []byte) string {
    75  	t.Helper()
    76  
    77  	name := fmt.Sprintf("%s.trace.", testName)
    78  	f, err := os.CreateTemp(t.ArtifactDir(), name)
    79  	if err != nil {
    80  		t.Fatalf("creating temp file: %v", err)
    81  	}
    82  	defer f.Close()
    83  	if _, err := io.Copy(f, bytes.NewReader(b)); err != nil {
    84  		t.Fatalf("writing trace dump to %q: %v", f.Name(), err)
    85  	}
    86  	return f.Name()
    87  }
    88  

View as plain text