Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion pkg/tracing/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,21 @@ func NewProviderFromEnv(ctx context.Context, resourceOptions ...resource.Option)
resourceOptions,
// Allow environment variables to override constant attributes provided by the caller.
resource.WithFromEnv(),
resource.WithProcess(),
// We need to replace the default implementation of WithProcessOwner, as it can fail
// if there is no passwd file (for example in Docker containers without /etc/passwd
// but with CGO enabled). However, there is no straight-forward way to produce a new
// With... grouping, due to package visibility rules. (And there is no way, also due
// to visibility, to replace the default process owner provider.) So we have to enumerate
// _all_ the calls WithProcess is equivalent to, so we can change the process owner
// implementation.
resource.WithProcessPID(),
resource.WithProcessExecutableName(),
resource.WithProcessExecutablePath(),
resource.WithProcessCommandArgs(),
WithSafeProcessOwner(),
resource.WithProcessRuntimeName(),
resource.WithProcessRuntimeVersion(),
resource.WithProcessRuntimeDescription(),
)...,
)
if err != nil {
Expand Down
46 changes: 46 additions & 0 deletions pkg/tracing/resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package tracing

import (
"context"
"fmt"
"os"
"os/user"

"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
)

type safeProcessOwnerProvider struct{}

var _ resource.Detector = safeProcessOwnerProvider{}

func (safeProcessOwnerProvider) Detect(context.Context) (*resource.Resource, error) {
// Re-implement the username logic of
// https://cs.opensource.google/go/go/+/refs/tags/go1.19.5:src/os/user/lookup_stubs.go
// so we can use the same rules in CGO mode as well.
username := os.Getenv("USER")
if u, err := user.Current(); err == nil {
username = u.Username
}

// Instead of returning an empty user, just convert the ID number to a string
// and use that -- so we always provide some sort of user. (Like the 'id' program
// would do.) This will allow us tostill provide some form of owner attribute
// regardless of any mismatch amongst the Docker USER parameter, the
// /etc/passwd file, the Kubernetes runAsUser setting...
if username == "" {
// ...but on Windows id will be -1: ignore all negatives.
if id := os.Getuid(); id >= 0 {
username = fmt.Sprintf("%d", id)
} else {
// Just give up.
return resource.Empty(), nil
}
}

return resource.NewWithAttributes(semconv.SchemaURL, semconv.ProcessOwnerKey.String(username)), nil
}

func WithSafeProcessOwner() resource.Option {
return resource.WithDetectors(safeProcessOwnerProvider{})
}