Skip to content

Commit d657f28

Browse files
committed
Update example and documentation
1 parent 97243b3 commit d657f28

File tree

3 files changed

+72
-36
lines changed

3 files changed

+72
-36
lines changed

README.md

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
# .Net diagnostics
22

3-
*Work In Progress*
4-
53
The package provides means for .Net runtime diagnostics implemented in Golang:
64
- [Diagnostics IPC Protocol](https://github.com/dotnet/diagnostics/blob/main/documentation/design-docs/ipc-protocol.md#transport) client.
75
- [NetTrace](https://github.com/microsoft/perfview/blob/main/src/TraceEvent/EventPipe/EventPipeFormat.md) decoder.
86

9-
### Diagnostics IPC Protocol Client
7+
### Diagnostic IPC Client
8+
9+
```
10+
# go get github.com/pyroscope-io/dotnetdiag
11+
```
1012

1113
Supported .Net versions:
1214
- .Net 5.0
@@ -26,4 +28,17 @@ Implemented commands:
2628
- [ ] ProcessInfo
2729
- [ ] ResumeRuntime
2830

29-
See [examples](examples) directory.
31+
### NetTrace decoder
32+
33+
```
34+
# go get github.com/pyroscope-io/dotnetdiag/nettrace
35+
```
36+
37+
Supported format versions: <= 4
38+
39+
The decoder deserializes `NetTrace` binary stream to the object sequence. The package also provides an example stream
40+
handler implementation which processes **Microsoft-DotNETCore-SampleProfiler**
41+
events: [github.com/pyroscope-io/dotnetdiag/nettrace/profiler](github.com/pyroscope-io/dotnetdiag/nettrace/profiler).
42+
43+
See [examples](examples) directory.
44+

examples/tracing/README.md

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,16 @@
11
# Collect Tracing
22

3-
The example demonstrates how the package may be used to collect NetTrace stream data using Diagnostics IPC:
4-
the program streams traces produced with `Microsoft-DotNETCore-SampleProfiler` provider to a file.
3+
The example demonstrates how the package may be used to collect and process `NetTrace` stream data using Diagnostics IPC:
4+
the program processes events produced with **Microsoft-DotNETCore-SampleProfiler** provider and creates a sampled profile,
5+
rendered as a call tree.
56

67
1. Run dotnet application.
78
2. Find its PID, e.g.:
89
```
910
# dotnet-trace ps
1011
```
1112

12-
3. Find Diagnostics IPC socket/pipe created by the application, e.g.:
13-
- Linux/MacOS:
14-
```
15-
# lsof -p {PID} | grep dotnet-diagnostic
16-
```
17-
18-
4. Run the example program:
19-
```
20-
# collect -s {absolute-path-to-socket} -o {path-to-nettrace-output-file}
21-
```
22-
23-
5. (Optional) Verify output file:
13+
3. Build and run the example program:
2414
```
25-
# dotnet-trace convert --format speedscope -o {path-to-output-file} {path-to-nettrace-file}
15+
# go run ./examples/tracing -p {pid}
2616
```

examples/tracing/collect.go

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,30 @@ package main
22

33
import (
44
"flag"
5+
"fmt"
56
"io"
67
"log"
78
"os"
89
"os/signal"
10+
"strconv"
11+
"strings"
912

1013
"github.com/pyroscope-io/dotnetdiag"
14+
"github.com/pyroscope-io/dotnetdiag/nettrace"
15+
"github.com/pyroscope-io/dotnetdiag/nettrace/profiler"
1116
)
1217

1318
func main() {
14-
var (
15-
socketFilePath string
16-
outputFilePath = "my-traces.nettrace"
17-
)
18-
19-
flag.StringVar(&socketFilePath, "s", "", "Path to Diagnostic IPC socket")
20-
flag.StringVar(&outputFilePath, "o", "my-traces.nettrace", "Output file.")
19+
var ps string
20+
flag.StringVar(&ps, "p", "", "Target process ID")
2121
flag.Parse()
2222

23-
if socketFilePath == "" {
24-
log.Fatalln("Diagnostic IPC socket path is required.")
25-
}
26-
27-
file, err := os.Create(outputFilePath)
23+
pid, err := strconv.Atoi(ps)
2824
if err != nil {
29-
log.Fatalln(err)
25+
log.Fatalln("Invalid PID:", err)
3026
}
31-
defer file.Close()
3227

33-
c := dotnetdiag.NewClient(socketFilePath)
28+
c := dotnetdiag.NewClient(dotnetdiag.DefaultServerAddress(pid))
3429
ctc := dotnetdiag.CollectTracingConfig{
3530
CircularBufferSizeMB: 10,
3631
Providers: []dotnetdiag.ProviderConfig{
@@ -57,9 +52,45 @@ func main() {
5752
}
5853
}()
5954

60-
if _, err = io.Copy(file, sess); err != nil {
55+
// Process the stream with the sample profiler.
56+
stream := nettrace.NewStream(sess)
57+
trace, err := stream.Open()
58+
if err != nil {
59+
_ = sess.Close()
6160
log.Fatalln(err)
6261
}
6362

64-
log.Println("Done")
63+
p := profiler.NewSampleProfiler(trace)
64+
stream.EventHandler = p.EventHandler
65+
stream.MetadataHandler = p.MetadataHandler
66+
stream.StackBlockHandler = p.StackBlockHandler
67+
stream.SequencePointBlockHandler = p.SequencePointBlockHandler
68+
69+
log.Println("Collecting trace log")
70+
for {
71+
switch err = stream.Next(); err {
72+
default:
73+
log.Fatalln(err)
74+
case nil:
75+
continue
76+
case io.EOF:
77+
p.Walk(treePrinter(os.Stdout))
78+
log.Println("Done")
79+
return
80+
}
81+
}
82+
}
83+
84+
func treePrinter(w io.Writer) func(profiler.FrameInfo) {
85+
return func(frame profiler.FrameInfo) {
86+
_, _ = fmt.Fprintf(w, "%s(%v) %s\n", padding(frame.Level), frame.SampledTime, frame.Name)
87+
}
88+
}
89+
90+
func padding(x int) string {
91+
var s strings.Builder
92+
for i := 0; i < x; i++ {
93+
s.WriteString("\t")
94+
}
95+
return s.String()
6596
}

0 commit comments

Comments
 (0)