Skip to content

Commit 0b3dca3

Browse files
mjcheethamclaude
andcommitted
config: add platform-agnostic 'target' property
Today the receiver config requires platform-specific fields to specify the listen path: 'pipe' on Windows (a named pipe path) and 'socket' on Unix (a Unix domain socket path). This means configs that use environment variable substitution via the ${env:VAR} syntax cannot use a single property that works across both platforms, since the field name itself is platform-specific. Add a new 'target' field that acts as a platform-agnostic alternative. During Validate(), when 'target' is set, its value is copied into the appropriate platform-specific field: NamedPipePath on Windows and UnixSocketPath on Unix. The existing normalization logic then handles the value as usual, including named pipe prefix expansion on Windows and af_unix: prefix stripping on Unix. Example usage: ```yaml receivers: trace2receiver: target: ${env:TRACE2_TARGET} ``` Unix: ``` TRACE2_TARGET=af_unix:/var/trace2.socket ./otel --config config.yaml ``` Windows: ``` SET TRACE2_TARGET //./pipe/trace2 otel --config config.yaml ``` It is an error to specify both 'target' and the platform-specific field ('pipe' or 'socket'), since the intent would be ambiguous. Add tests covering the target-to-socket mapping on Unix (with and without af_unix: prefix), the target-to-pipe mapping on Windows, and the conflict error for both platforms. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
1 parent 222a5ba commit 0b3dca3

5 files changed

Lines changed: 149 additions & 25 deletions

File tree

Docs/Examples/DebugDump/config.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616

1717
receivers:
1818
trace2receiver:
19-
socket: "/usr/local/<my-install-dir>/trace2.socket"
20-
pipe: "//./pipe/<my-pipe-name>"
19+
target: ${env:TRACE2_TARGET}
2120

2221
# filter: "/usr/local/<my-install-dir>/filter.yml"
2322
# pii: "/usr/local/<my-install-dir>/pii.yml"

Docs/Examples/ExportToAzureMonitor/config.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515

1616
receivers:
1717
trace2receiver:
18-
socket: "/usr/local/<my-install-dir>/trace2.socket"
19-
pipe: "//./pipe/<my-pipe-name>"
18+
target: ${env:TRACE2_TARGET}
2019

2120
# filter: "/usr/local/<my-install-dir>/filter.yml"
2221
# pii: "/usr/local/<my-install-dir>/pii.yml"

Docs/configure-custom-collector.md

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ The `trace2receiver` component has the following config values:
4242
```
4343
receivers:
4444
trace2receiver:
45-
socket: <unix-domain-socket-pathname>
46-
pipe: <windows-named-pipe-pathname>
45+
target: <trace2-target>
4746
pii: <pii-settings-pathname>
4847
filter: <filter-settings-pathname>
4948
```
@@ -53,17 +52,26 @@ For example:
5352
```
5453
receivers:
5554
trace2receiver:
56-
socket: "/usr/local/my-collector/trace2.socket"
57-
pipe: "//./pipe/my-collector.pipe"
55+
target: "/usr/local/my-collector/trace2.socket"
5856
pii: "/usr/local/my-collector/pii.yml"
5957
filter: "/usr/local/my-collector/filter.yml"
6058
```
6159

62-
### `<unix-domain-socket-pathname>` (Required on Unix)
60+
### `<trace2-target>` (Required)
6361

64-
The pathname will be used on Linux and macOS hosts to create a Unix
65-
Domain Socket where the receiver will listen for telemetry from Git
66-
commands. The socket will be created when the collector starts up.
62+
The `target` property is a string that specifies where the `trace2receiver`
63+
should listen for Trace2 telemetry from Git commands. This is required.
64+
It must be a pathname to a Unix Domain Socket on Unix hosts, or a pathname to a
65+
Windows Named Pipe on Windows hosts. The collector will create the socket or
66+
named pipe when it starts up. The `target` property can be specified directly
67+
as a string literal, or it can be specified indirectly using an environment
68+
variable. For example:
69+
70+
```
71+
receivers:
72+
trace2receiver:
73+
target: ${env:TRACE2_TARGET}
74+
```
6775

6876
To tell Git to send Trace2 telemetry to the receiver, you must set
6977
the Git `trace2.eventtarget` config setting at the `global` or
@@ -74,14 +82,34 @@ and
7482
[enabling a target](https://git-scm.com/docs/api-trace2#_enabling_a_target)
7583
for details.
7684

85+
#### Unix
7786
```
7887
$ git config --system trace2.eventtarget "af_unix:/usr/local/my-collector/trace2.socket"
7988
```
8089

8190
_The `af_unix:` prefix is required to tell Git that it should expect a
8291
Unix Domain Socket rather than a plain file._
8392

84-
### `<windows-named-pipe-pathname>` (Required on Windows)
93+
#### Windows
94+
```
95+
$ git config --system trace2.eventtarget "//./pipe/my-collector.pipe"
96+
```
97+
98+
_The `//./pipe/` prefix is required to tell Git that it should expect a
99+
Windows Named Pipe rather than a plain file._
100+
101+
### `<unix-domain-socket-pathname>` (Unix-only, deprecated)
102+
103+
The pathname will be used on Linux and macOS hosts to create a Unix
104+
Domain Socket where the receiver will listen for telemetry from Git
105+
commands. The socket will be created when the collector starts up.
106+
107+
Replaced by the more general `<trace2-target>` config value, which can be used
108+
on all platforms. It is an error to set both `target` and
109+
`unix-domain-socket-pathname`. If both are set, then then collector will fail to
110+
start.
111+
112+
### `<windows-named-pipe-pathname>` (Windows-only, deprecated)
85113

86114
The pathname will be used on Windows hosts to create a Windows Named
87115
Pipe where the receiver will listen for telemetry from Git commands.
@@ -90,18 +118,10 @@ pathname must refer to a local named pipe `//./pipe/...` because named
90118
pipe servers can only create and listen on local pipes. You may use
91119
forward or backslashes.
92120

93-
To tell Git to send Trace2 telemetry to the receiver, you must set
94-
the Git `trace2.eventtarget` config setting at the `global` or
95-
`system` level to this named pipe pathname. See the Git Trace2 API
96-
documentation on the
97-
[event format target](https://git-scm.com/docs/api-trace2#_the_event_format_target)
98-
and
99-
[enabling a target](https://git-scm.com/docs/api-trace2#_enabling_a_target)
100-
for details.
101-
102-
```
103-
$ git config --system trace2.eventtarget "//./pipe/my-collector.pipe"
104-
```
121+
Replaced by the more general `<trace2-target>` config value, which can be used
122+
on all platforms. It is an error to set both `target` and
123+
`windows-named-pipe-pathname`. If both are set, then then collector will fail to
124+
start.
105125

106126
### `<pii-settings-pathname>` (Optional)
107127

config.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ type Config struct {
4141
// This config file field is ignored on Windows platforms.
4242
UnixSocketPath string `mapstructure:"socket"`
4343

44+
// A combination of either a NamedPipePath or a UnixSocketPath.
45+
// On Unix this can only be considered as a Unix domain socket,
46+
// and on Windows we can only consider it as a named pipe.
47+
// This allows the user to specify a property that works for
48+
// either platform, and we will normalize it to the correct one
49+
// at runtime. If both are specified we consider this an error.
50+
// The idea behind this is to allow users to specify the value
51+
// of the Target property as an environment variable via the
52+
// ${env:VAR} syntax, and then use that environment variable to
53+
// set the correct path for their platform.
54+
Target string `mapstructure:"target"`
55+
4456
// Allow command and control verbs to be embedded in the Trace2
4557
// data stream.
4658
AllowCommandControlVerbs bool `mapstructure:"enable_commands"`
@@ -79,6 +91,23 @@ func (cfg *Config) Validate() error {
7991
var path string
8092
var err error
8193

94+
// If `target` is set, normalize it into the platform-specific
95+
// field. It is an error to set both `target` and the
96+
// platform-specific field.
97+
if len(cfg.Target) > 0 {
98+
if runtime.GOOS == "windows" {
99+
if len(cfg.NamedPipePath) > 0 {
100+
return fmt.Errorf("receivers.trace2receiver: cannot specify both 'target' and 'pipe'")
101+
}
102+
cfg.NamedPipePath = cfg.Target
103+
} else {
104+
if len(cfg.UnixSocketPath) > 0 {
105+
return fmt.Errorf("receivers.trace2receiver: cannot specify both 'target' and 'socket'")
106+
}
107+
cfg.UnixSocketPath = cfg.Target
108+
}
109+
}
110+
82111
if runtime.GOOS == "windows" {
83112
if len(cfg.NamedPipePath) == 0 {
84113
return fmt.Errorf("receivers.trace2receiver.pipe not defined")

config_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,83 @@ func Test_Config_Validate_WithCommandControlEnabled(t *testing.T) {
356356
assert.NoError(t, err)
357357
}
358358

359+
// Test Validate with Target on Unix sets UnixSocketPath
360+
func Test_Config_Validate_TargetUnix(t *testing.T) {
361+
if runtime.GOOS == "windows" {
362+
t.Skip("Skipping Unix-specific test")
363+
}
364+
365+
cfg := &Config{
366+
Target: "/tmp/test.socket",
367+
}
368+
369+
err := cfg.Validate()
370+
assert.NoError(t, err)
371+
assert.Equal(t, "/tmp/test.socket", cfg.UnixSocketPath)
372+
}
373+
374+
// Test Validate with Target with af_unix prefix on Unix
375+
func Test_Config_Validate_TargetAfUnixPrefixUnix(t *testing.T) {
376+
if runtime.GOOS == "windows" {
377+
t.Skip("Skipping Unix-specific test")
378+
}
379+
380+
cfg := &Config{
381+
Target: "af_unix:/tmp/test.socket",
382+
}
383+
384+
err := cfg.Validate()
385+
assert.NoError(t, err)
386+
assert.Equal(t, "/tmp/test.socket", cfg.UnixSocketPath)
387+
}
388+
389+
// Test Validate with Target on Windows sets NamedPipePath
390+
func Test_Config_Validate_TargetWindows(t *testing.T) {
391+
if runtime.GOOS != "windows" {
392+
t.Skip("Skipping Windows-specific test")
393+
}
394+
395+
cfg := &Config{
396+
Target: "test-pipe",
397+
}
398+
399+
err := cfg.Validate()
400+
assert.NoError(t, err)
401+
assert.Equal(t, `\\.\pipe\test-pipe`, cfg.NamedPipePath)
402+
}
403+
404+
// Test Validate rejects Target and socket both set on Unix
405+
func Test_Config_Validate_TargetAndSocketConflictUnix(t *testing.T) {
406+
if runtime.GOOS == "windows" {
407+
t.Skip("Skipping Unix-specific test")
408+
}
409+
410+
cfg := &Config{
411+
Target: "/tmp/target.socket",
412+
UnixSocketPath: "/tmp/test.socket",
413+
}
414+
415+
err := cfg.Validate()
416+
assert.Error(t, err)
417+
assert.Contains(t, err.Error(), "cannot specify both 'target' and 'socket'")
418+
}
419+
420+
// Test Validate rejects Target and pipe both set on Windows
421+
func Test_Config_Validate_TargetAndPipeConflictWindows(t *testing.T) {
422+
if runtime.GOOS != "windows" {
423+
t.Skip("Skipping Windows-specific test")
424+
}
425+
426+
cfg := &Config{
427+
Target: "target-pipe",
428+
NamedPipePath: "test-pipe",
429+
}
430+
431+
err := cfg.Validate()
432+
assert.Error(t, err)
433+
assert.Contains(t, err.Error(), "cannot specify both 'target' and 'pipe'")
434+
}
435+
359436
// Helper function to create a minimal valid config for the current platform
360437
func createMinimalValidConfig() *Config {
361438
if runtime.GOOS == "windows" {

0 commit comments

Comments
 (0)