Repository: rakyll/go-test-trace
Branch: main
Commit: d5d0002685b0
Files: 12
Total size: 30.1 KB
Directory structure:
gitextract_w0avwwzi/
├── .circleci/
│ └── config.yml
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── example/
│ ├── collector.yaml
│ └── example_test.go
├── go.mod
├── go.sum
├── main.go
├── parser.go
└── parser_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .circleci/config.yml
================================================
# Golang CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-go/ for more details
version: 2
jobs:
build:
docker:
# specify the version
- image: circleci/golang:1.16
working_directory: /go/src/github.com/rakyll/go-test-trace
steps:
- checkout
# specify any bash command here prefixed with `run: `
- run: go test $(go list ./... | grep -v /example) -v ./...
================================================
FILE: .gitignore
================================================
bin/*
================================================
FILE: LICENSE
================================================
Copyright (c) 2021 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: Makefile
================================================
default:
go run main.go parser.go ./example
stdin:
go test -v -count=1 ./example | go run main.go parser.go -stdin
================================================
FILE: README.md
================================================
# go-test-trace
[](https://circleci.com/gh/rakyll/go-test-trace/tree/main)
go-test-trace is like go test but it also generates
distributed traces.
Generated traces are exported in OTLP to a
[OpenTelemetry collector](https://github.com/open-telemetry/opentelemetry-collector).
You need to run go-test-trace alongside a collector to export data to
distributed tracing service.

## Installation
```
go get -u github.com/rakyll/go-test-trace
```
## Usage
You can use go-test-trace as a drop-in replacement for go test.
The following example will generate a distributed trace
and export it to a collector available at "127.0.0.1:55680".
```
$ go-test-trace ./example
=== RUN TestStart
--- PASS: TestStart (0.50s)
=== RUN TestStartWithOptions
--- PASS: TestStartWithOptions (1.00s)
=== RUN TestFileParser
--- FAIL: TestFileParser (0.30s)
=== RUN TestLoading
=== PAUSE TestLoading
=== RUN TestLoading_abort
=== PAUSE TestLoading_abort
=== RUN TestLoading_interrupt
=== PAUSE TestLoading_interrupt
=== CONT TestLoading
=== CONT TestLoading_abort
=== CONT TestLoading_interrupt
--- PASS: TestLoading_interrupt (0.08s)
--- PASS: TestLoading (1.00s)
--- PASS: TestLoading_abort (2.50s)
FAIL
FAIL github.com/rakyll/go-test-trace/example 4.823s
exit status 1
make: *** [default] Error 1
```
Alternatively, you can use -stdin option to parse
the output of go test. This option won't be as accurate
in terms of timestamps because it will generate trace spans
as it sees output in stdin.
```
$ go test -v ./example | go-test-trace -stdin
```
You can export to any collector by using the endpoint flag:
```
$ go-test-trace -endpoint=my-otel-collector.io:9090 ./example
```
You can make the go-test-trace to participate into an existing
trace with the traceparent flag.
```
$ go-test-trace -traceparent=00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01 ./example
```
## Running the collector
An example collector configuration is available at example/collector.yaml.
It exports to Honeycomb but you can choose to any other destination by
changing the configuration. Please edit the write key and data set
with your details from Honeycomb before using it.
Then, you can run the collector locally by the following command
and export the traces to Honeycomb:
```
$ docker run --rm -p 4317:4317 -p 55680:55680 -p 8888:8888 \
-v "${PWD}/example/collector.yaml":/collector.yaml \
--name awscollector public.ecr.aws/aws-observability/aws-otel-collector:latest \
--config collector.yaml;
```
You can use any configuration supported by [ADOT](https://github.com/aws-observability/aws-otel-collector)
or export to any other OpenTelemetry collector.
================================================
FILE: example/collector.yaml
================================================
# You can modify this file with any component
# available at https://github.com/aws-observability/aws-otel-collector#aws-otel-collector-built-in-components.
# If you want to use components not supported
# in this distribution, please feel free to use your
# own distribution.
receivers:
otlp:
protocols:
grpc:
http:
processors:
exporters:
otlp:
endpoint: api.honeycomb.io:443
headers:
"x-honeycomb-team": "<INSERT WRITE KEY>"
"x-honeycomb-dataset": "<INSERT DATASET>"
logging:
loglevel: debug
service:
pipelines:
traces:
receivers: [otlp]
processors: []
exporters: [logging, otlp]
================================================
FILE: example/example_test.go
================================================
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package example
import (
"testing"
"time"
)
func TestStart(t *testing.T) {
time.Sleep(500 * time.Millisecond)
}
func TestStartWithOptions(t *testing.T) {
time.Sleep(1000 * time.Millisecond)
}
func TestFileParser(t *testing.T) {
time.Sleep(300 * time.Millisecond)
t.Fail()
}
func TestLoading(t *testing.T) {
t.Parallel()
time.Sleep(time.Second)
}
func TestLoading_abort(t *testing.T) {
t.Parallel()
time.Sleep(2500 * time.Millisecond)
}
func TestLoading_interrupt(t *testing.T) {
t.Parallel()
time.Sleep(80 * time.Millisecond)
}
================================================
FILE: go.mod
================================================
module github.com/rakyll/go-test-trace
go 1.14
require (
go.opentelemetry.io/otel v1.0.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.0
go.opentelemetry.io/otel/sdk v1.0.0
go.opentelemetry.io/otel/trace v1.0.0
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167 // indirect
golang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0 // indirect
)
================================================
FILE: go.sum
================================================
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.opentelemetry.io/otel v1.0.0 h1:qTTn6x71GVBvoafHK/yaRUmFzI4LcONZD0/kXxl5PHI=
go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.0 h1:Vv4wbLEjheCTPV07jEav7fyUpJkyftQK7Ss2G7qgdSo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.0/go.mod h1:3VqVbIbjAycfL1C7sIu/Uh/kACIUPWHztt8ODYwR3oM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.0 h1:B9VtEB1u41Ohnl8U6rMCh1jjedu8HwFh4D0QeB+1N+0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.0/go.mod h1:zhEt6O5GGJ3NCAICr4hlCPoDb2GQuh4Obb4gZBgkoQQ=
go.opentelemetry.io/otel/sdk v1.0.0 h1:BNPMYUONPNbLneMttKSjQhOTlFLOD9U22HNG1KrIN2Y=
go.opentelemetry.io/otel/sdk v1.0.0/go.mod h1:PCrDHlSy5x1kjezSdL37PhbFUMjrsLRshJ2zCzeXwbM=
go.opentelemetry.io/otel/trace v1.0.0 h1:TSBr8GTEtKevYMG/2d21M989r5WJYVimhTHBKVEZuh4=
go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.9.0 h1:C0g6TWmQYvjKRnljRULLWUVJGy8Uvu0NEL/5frY2/t4=
go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167 h1:eDd+TJqbgfXruGQ5sJRU7tEtp/58OAx4+Ayjxg4SM+4=
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7 h1:c20P3CcPbopVp2f7099WLOqSNKURf30Z0uq66HpijZY=
golang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0 h1:5Tbluzus3QxoAJx4IefGt1W0HQZW4nuMrVk684jI74Q=
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
================================================
FILE: main.go
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// go-test-trace is a tiny program that generates OpenTelemetry
// traces when testing a Go package.
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"os"
"os/exec"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
oteltrace "go.opentelemetry.io/otel/trace"
)
var (
endpoint string
name string
stdin bool
traceparent string
help bool
)
type spanData struct {
span oteltrace.Span
startTime time.Time
}
var collectedSpans = make(map[string]*spanData, 1000)
func main() {
fset := flag.NewFlagSet("", flag.ContinueOnError)
fset.StringVar(&endpoint, "endpoint", "127.0.0.1:55680", "")
fset.StringVar(&name, "name", "go-test-trace", "")
fset.BoolVar(&stdin, "stdin", false, "")
fset.BoolVar(&help, "help", false, "")
fset.StringVar(&traceparent, "traceparent", "", "")
fset.Usage = func() {} // don't error instead pass remaining arguments to go test
fset.Parse(os.Args[1:])
if help {
fmt.Println(usageText)
os.Exit(0)
}
if err := trace(fset.Args()); err != nil {
log.Fatal(err)
}
}
func trace(args []string) error {
ctx := context.Background()
traceExporter, err := otlptracegrpc.New(ctx,
otlptracegrpc.WithInsecure(),
otlptracegrpc.WithEndpoint(endpoint),
otlptracegrpc.WithTimeout(100*time.Millisecond),
)
if err != nil {
return err
}
res, err := resource.New(ctx, resource.WithAttributes(
semconv.ServiceNameKey.String("go test"),
))
if err != nil {
return err
}
tracerProvider := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithSpanProcessor(sdktrace.NewSimpleSpanProcessor(traceExporter)),
sdktrace.WithResource(res),
)
otel.SetTracerProvider(tracerProvider)
t := otel.Tracer(name)
// If there is a parent trace, participate into it.
// If not, create a new root span.
if traceparent != "" {
propagation := propagation.TraceContext{}
ctx = propagation.Extract(ctx, &carrier{traceparent: traceparent})
}
globalCtx, globalSpan := t.Start(ctx, name)
defer func() {
globalSpan.End()
if err := tracerProvider.Shutdown(context.Background()); err != nil {
log.Printf("Failed shutting down the tracer provider: %v", err)
}
}()
if stdin {
p, err := newParser(globalCtx, t)
if err != nil {
return err
}
return p.parse(os.Stdin)
}
// Otherwise, act like a drop-in replacement for `go test`.
goTestArgs := append([]string{"test"}, args...)
goTestArgs = append(goTestArgs, "-json")
cmd := exec.Command("go", goTestArgs...)
cmd.Env = append(
os.Environ(),
fmt.Sprintf("TRACEPARENT=%q", globalSpan.SpanContext().TraceID()),
)
r, err := cmd.StdoutPipe()
if err != nil {
log.Fatal(err)
}
decoder := json.NewDecoder(r)
go func() {
for decoder.More() {
var data goTestOutput
if err := decoder.Decode(&data); err != nil {
if err == io.EOF {
return
}
log.Printf("Failed to decode JSON: %v", err)
}
switch data.Action {
case "run":
var span oteltrace.Span
_, span = t.Start(globalCtx, data.Test, oteltrace.WithTimestamp(data.Time))
collectedSpans[data.Test] = &spanData{
span: span,
startTime: data.Time,
}
case "pass", "fail", "skip":
if data.Test == "" {
continue
}
spanData, ok := collectedSpans[data.Test]
if !ok {
return // should never happen
}
if data.Action == "fail" {
spanData.span.SetStatus(codes.Error, "")
}
spanData.span.End(oteltrace.WithTimestamp(data.Time))
}
fmt.Print(data.Output)
}
}()
return cmd.Run()
}
type goTestOutput struct {
Time time.Time
Action string
Test string
Output string
}
type carrier struct{ traceparent string }
func (c *carrier) Get(key string) string {
if key == "traceparent" {
return c.traceparent
}
return ""
}
func (c *carrier) Set(key string, value string) {
panic("not implemented")
}
func (c *carrier) Keys() []string {
return []string{"traceparent"}
}
const usageText = `Usage:
go-test-trace [flags...] [go test flags...]
Flags:
-name Name of the trace span created for the test, optional.
-endpoint OpenTelemetry gRPC collector endpoint, 127.0.0.1:55680 by default.
-traceparent Trace to participate into if any, in W3C Trace Context format.
-stdin Parse go test verbose output from stdin.
-help Print this text.
Run "go help test" for go test flags.`
================================================
FILE: parser.go
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bufio"
"context"
"fmt"
"io"
"regexp"
"strings"
"time"
"go.opentelemetry.io/otel/codes"
oteltrace "go.opentelemetry.io/otel/trace"
)
type parser struct {
globalCtx context.Context
tracer oteltrace.Tracer
}
func newParser(ctx context.Context, tracer oteltrace.Tracer) (*parser, error) {
return &parser{globalCtx: ctx, tracer: tracer}, nil
}
func (p *parser) parse(r io.Reader) error {
reader := bufio.NewReader(r)
for {
l, _, err := reader.ReadLine()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
p.parseLine(string(l))
}
}
func (p *parser) parseLine(line string) {
defer fmt.Printf("%s\n", line)
trimmed := strings.TrimSpace(line)
switch {
case strings.HasPrefix(trimmed, "ok"):
// Do nothing.
case strings.HasPrefix(trimmed, "PASS"):
// Do nothing.
case strings.HasPrefix(trimmed, "FAIL"):
// Do nothing.
case strings.Contains(trimmed, "[no test files]"):
// Do nothing.
case strings.HasPrefix(trimmed, "--- SKIP"):
// TODO(jbd): Annotate.
case strings.HasPrefix(trimmed, "=== RUN"):
// start span
p.startSpanForLine(trimmed)
case strings.HasPrefix(trimmed, "--- PASS"):
// end span
p.endSpanForLine(trimmed, false)
case strings.HasPrefix(trimmed, "--- FAIL"):
// end span with error
p.endSpanForLine(trimmed, true)
}
}
func (p *parser) startSpanForLine(line string) error {
name := parseName(line)
_, span := p.tracer.Start(p.globalCtx, name)
collectedSpans[name] = &spanData{
span: span,
startTime: time.Now(),
}
return nil
}
func (p *parser) endSpanForLine(line string, errored bool) {
name, dur := parseNameAndDuration(line)
data, ok := collectedSpans[name]
if !ok {
return
}
if errored {
data.span.SetStatus(codes.Error, "")
}
data.span.End(oteltrace.WithTimestamp(data.startTime.Add(dur)))
}
func parseName(line string) string {
return testNameRegex.FindAllStringSubmatch(line, -1)[0][0]
}
func parseNameAndDuration(line string) (string, time.Duration) {
m := testNameWithDurationRegex.FindAllStringSubmatch(line, -1)
name := m[0][1]
duration := m[0][2]
dur, _ := time.ParseDuration(duration)
return name, dur
}
var (
testNameRegex = regexp.MustCompile(`(Test.+)`)
testNameWithDurationRegex = regexp.MustCompile(`(Test.+)\s\(([\w|\.]+)\)`)
)
================================================
FILE: parser_test.go
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// gotest is a tiny program that shells out to `go test`
// and prints the output in color.
package main
import (
"testing"
"time"
)
func TestParseNameAndDuration(t *testing.T) {
tests := []struct {
description string
line string
wantName string
wantDur string
}{
{
description: "pass sub test",
line: " --- PASS: TestGetConfig/otlp#01 (1.50s)",
wantName: "TestGetConfig/otlp#01",
wantDur: "1.5s",
},
{
description: "fail sub test",
line: " --- FAIL: TestGetConfig/otlp#01 (1.50s)",
wantName: "TestGetConfig/otlp#01",
wantDur: "1.5s",
},
}
for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
name, dur := parseNameAndDuration(tt.line)
if name != tt.wantName {
t.Errorf("parseNameAndDuration() name = %v, want %v", name, tt.wantName)
}
parsedWantDur, _ := time.ParseDuration(tt.wantDur)
if dur != parsedWantDur {
t.Errorf("parseNameAndDuration() duration = %v, want %v", dur, tt.wantDur)
}
})
}
}
gitextract_w0avwwzi/ ├── .circleci/ │ └── config.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── example/ │ ├── collector.yaml │ └── example_test.go ├── go.mod ├── go.sum ├── main.go ├── parser.go └── parser_test.go
SYMBOL INDEX (24 symbols across 4 files)
FILE: example/example_test.go
function TestStart (line 12) | func TestStart(t *testing.T) {
function TestStartWithOptions (line 16) | func TestStartWithOptions(t *testing.T) {
function TestFileParser (line 20) | func TestFileParser(t *testing.T) {
function TestLoading (line 25) | func TestLoading(t *testing.T) {
function TestLoading_abort (line 30) | func TestLoading_abort(t *testing.T) {
function TestLoading_interrupt (line 35) | func TestLoading_interrupt(t *testing.T) {
FILE: main.go
type spanData (line 38) | type spanData struct
function main (line 45) | func main() {
function trace (line 64) | func trace(args []string) error {
type goTestOutput (line 160) | type goTestOutput struct
type carrier (line 167) | type carrier struct
method Get (line 169) | func (c *carrier) Get(key string) string {
method Set (line 176) | func (c *carrier) Set(key string, value string) {
method Keys (line 180) | func (c *carrier) Keys() []string {
constant usageText (line 184) | usageText = `Usage:
FILE: parser.go
type parser (line 20) | type parser struct
method parse (line 29) | func (p *parser) parse(r io.Reader) error {
method parseLine (line 43) | func (p *parser) parseLine(line string) {
method startSpanForLine (line 75) | func (p *parser) startSpanForLine(line string) error {
method endSpanForLine (line 85) | func (p *parser) endSpanForLine(line string, errored bool) {
function newParser (line 25) | func newParser(ctx context.Context, tracer oteltrace.Tracer) (*parser, e...
function parseName (line 97) | func parseName(line string) string {
function parseNameAndDuration (line 101) | func parseNameAndDuration(line string) (string, time.Duration) {
FILE: parser_test.go
function TestParseNameAndDuration (line 14) | func TestParseNameAndDuration(t *testing.T) {
Condensed preview — 12 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (33K chars).
[
{
"path": ".circleci/config.yml",
"chars": 432,
"preview": "# Golang CircleCI 2.0 configuration file\n#\n# Check https://circleci.com/docs/2.0/language-go/ for more details\nversion: "
},
{
"path": ".gitignore",
"chars": 5,
"preview": "bin/*"
},
{
"path": "LICENSE",
"chars": 1479,
"preview": "Copyright (c) 2021 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or with"
},
{
"path": "Makefile",
"chars": 119,
"preview": "default:\n\tgo run main.go parser.go ./example\n\nstdin:\n\tgo test -v -count=1 ./example | go run main.go parser.go -stdin\n\n"
},
{
"path": "README.md",
"chars": 2800,
"preview": "# go-test-trace\n\n[](https://circleci.co"
},
{
"path": "example/collector.yaml",
"chars": 652,
"preview": "# You can modify this file with any component\n# available at https://github.com/aws-observability/aws-otel-collector#aws"
},
{
"path": "example/example_test.go",
"chars": 707,
"preview": "// Copyright 2020 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "go.mod",
"chars": 485,
"preview": "module github.com/rakyll/go-test-trace\n\ngo 1.14\n\nrequire (\n\tgo.opentelemetry.io/otel v1.0.0\n\tgo.opentelemetry.io/otel/ex"
},
{
"path": "go.sum",
"chars": 15667,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1"
},
{
"path": "main.go",
"chars": 4795,
"preview": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "parser.go",
"chars": 2479,
"preview": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "parser_test.go",
"chars": 1201,
"preview": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
}
]
About this extraction
This page contains the full source code of the rakyll/go-test-trace GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 12 files (30.1 KB), approximately 12.9k tokens, and a symbol index with 24 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.