Skip to content

Commit c22867d

Browse files
authored
Merge pull request #4 from pyroscope-io/windows-support
Windows support
2 parents 27769c5 + 1a0bc21 commit c22867d

File tree

7 files changed

+85
-22
lines changed

7 files changed

+85
-22
lines changed

README.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# .Net diagnostics
1+
# .NET diagnostics
22

33
The package provides means for .Net runtime diagnostics implemented in Golang:
44
- [Diagnostics IPC Protocol](https://github.com/dotnet/diagnostics/blob/main/documentation/design-docs/ipc-protocol.md#transport) client.
@@ -10,12 +10,12 @@ The package provides means for .Net runtime diagnostics implemented in Golang:
1010
# go get github.com/pyroscope-io/dotnetdiag
1111
```
1212

13-
Supported .Net versions:
14-
- .Net 5.0
15-
- .Net Core 3.1
13+
Supported .NET versions:
14+
- .NET 5.0
15+
- .NET Core 3.1
1616

1717
Supported platforms:
18-
- [ ] Windows
18+
- [x] Windows
1919
- [x] Linux
2020
- [x] MacOS
2121

client.go

+31-5
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,28 @@ import (
66
)
77

88
// Client implement Diagnostic IPC Protocol client.
9-
// https://github.com/dotnet/diagnostics/blob/main/documentation/design-docs/ipc-protocol.md#CollectStreaming
9+
// https://github.com/dotnet/diagnostics/blob/main/documentation/design-docs/ipc-protocol.md
1010
type Client struct {
1111
addr string
12+
dial Dialer
13+
}
14+
15+
// Dialer establishes connection to the given address. Due to the potential for
16+
// an optional continuation in the Diagnostics IPC Protocol, each successful
17+
// connection between the runtime and a Diagnostic Port is only usable once.
18+
//
19+
// Note that the dialer is OS-specific, refer to documentation for details:
20+
// https://github.com/dotnet/diagnostics/blob/main/documentation/design-docs/ipc-protocol.md#transport
21+
type Dialer func(addr string) (net.Conn, error)
22+
23+
// Option overrides default Client parameters.
24+
type Option func(*Client)
25+
26+
// WithDialer overrides default dialer function with d.
27+
func WithDialer(d Dialer) Option {
28+
return func(c *Client) {
29+
c.dial = d
30+
}
1231
}
1332

1433
// Session represents EventPipe stream of NetTrace data created with
@@ -44,16 +63,23 @@ type CollectTracingConfig struct {
4463
//
4564
// Refer to documentation for details:
4665
// https://github.com/dotnet/diagnostics/blob/main/documentation/design-docs/ipc-protocol.md#transport
47-
func NewClient(addr string) *Client {
48-
return &Client{addr: addr}
66+
func NewClient(addr string, options ...Option) *Client {
67+
c := &Client{addr: addr}
68+
for _, option := range options {
69+
option(c)
70+
}
71+
if c.dial == nil {
72+
c.dial = DefaultDialer()
73+
}
74+
return c
4975
}
5076

5177
// CollectTracing creates a new EventPipe session stream of NetTrace data.
5278
func (c *Client) CollectTracing(config CollectTracingConfig) (s *Session, err error) {
5379
// Every session has its own IPC connection which cannot be reused for any
5480
// other purposes; in order to close the connection another connection
5581
// to be opened - see `StopTracing`.
56-
conn, err := dial(c.addr)
82+
conn, err := c.dial(c.addr)
5783
if err != nil {
5884
return nil, err
5985
}
@@ -89,7 +115,7 @@ func (c *Client) CollectTracing(config CollectTracingConfig) (s *Session, err er
89115

90116
// StopTracing stops the given streaming session started with CollectTracing.
91117
func (c *Client) StopTracing(sessionID uint64) error {
92-
conn, err := dial(c.addr)
118+
conn, err := c.dial(c.addr)
93119
if err != nil {
94120
return err
95121
}

client_unix.go

+13-9
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,22 @@ import (
1010
"sort"
1111
)
1212

13-
func dial(addr string) (net.Conn, error) {
14-
ua := &net.UnixAddr{
15-
Name: addr,
16-
Net: "unix",
13+
func DefaultDialer() Dialer {
14+
return func(addr string) (net.Conn, error) {
15+
ua := &net.UnixAddr{
16+
Name: addr,
17+
Net: "unix",
18+
}
19+
conn, err := net.DialUnix("unix", nil, ua)
20+
if err != nil {
21+
return nil, err
22+
}
23+
return conn, nil
1724
}
18-
conn, err := net.DialUnix("unix", nil, ua)
19-
if err != nil {
20-
return nil, err
21-
}
22-
return conn, nil
2325
}
2426

27+
// DefaultServerAddress returns Diagnostic Server unix domain socket path for the process given.
28+
// https://github.com/dotnet/diagnostics/blob/main/documentation/design-docs/ipc-protocol.md#transport
2529
func DefaultServerAddress(pid int) string {
2630
paths, err := filepath.Glob(fmt.Sprintf("%s/dotnet-diagnostic-%d-*-socket", os.TempDir(), pid))
2731
if err != nil || len(paths) == 0 {

client_windows.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package dotnetdiag
2+
3+
import (
4+
"fmt"
5+
"net"
6+
7+
"github.com/Microsoft/go-winio"
8+
)
9+
10+
func DefaultDialer() Dialer {
11+
return func(addr string) (net.Conn, error) {
12+
return winio.DialPipe(addr, nil)
13+
}
14+
}
15+
16+
// DefaultServerAddress returns Diagnostic Server named pipe name for the process given.
17+
// https://github.com/dotnet/diagnostics/blob/main/documentation/design-docs/ipc-protocol.md#transport
18+
func DefaultServerAddress(pid int) string {
19+
return fmt.Sprintf(`\\.\pipe\dotnet-diagnostic-%d`, pid)
20+
}

go.mod

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@ module github.com/pyroscope-io/dotnetdiag
22

33
go 1.16
44

5-
require golang.org/x/text v0.3.6
5+
require (
6+
github.com/Microsoft/go-winio v0.5.0
7+
golang.org/x/text v0.3.6
8+
)

go.sum

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU=
2+
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
5+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
6+
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
7+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
8+
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
9+
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
10+
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
111
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
212
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
313
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

nettrace/profiler/profiler.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func (s *SampleProfiler) Samples() map[string]time.Duration {
104104
for i := range x.stack {
105105
name[i] = s.sym.resolve(x.stack[i])
106106
}
107-
samples[strings.Join(name, ";")] += time.Duration(x.value * -1)
107+
samples[strings.Join(name, ";")] += -time.Millisecond * time.Duration(x.value)
108108
}
109109
return samples
110110
}
@@ -172,7 +172,7 @@ func (s *SampleProfiler) addSample(e *nettrace.Blob) error {
172172
threadID: e.Header.ThreadID,
173173
stackID: e.Header.StackID,
174174
timestamp: e.Header.TimeStamp,
175-
relativeTime: e.Header.TimeStamp - s.trace.SyncTimeQPC,
175+
relativeTime: (e.Header.TimeStamp - s.trace.SyncTimeQPC) * 1000 / s.trace.QPCFrequency,
176176
})
177177
return nil
178178
}

0 commit comments

Comments
 (0)