Skip to content

Commit 6dd0549

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. 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 6dd0549

2 files changed

Lines changed: 106 additions & 0 deletions

File tree

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)