Skip to content

Commit

Permalink
Merge branch 'v1' into julio.guerra/monitor-grpc-metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
Julio-Guerra committed Mar 7, 2022
2 parents 417f7eb + 1dfcbe9 commit 7d80e0f
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 0 deletions.
38 changes: 38 additions & 0 deletions ddtrace/tracer/option.go
Expand Up @@ -829,3 +829,41 @@ func StackFrames(n, skip uint) FinishOption {
cfg.SkipStackFrames = skip
}
}

// UserMonitoringOption represents a function that can be provided as a parameter to SetUser.
type UserMonitoringOption func(Span)

// WithUserEmail returns the option setting the email of the authenticated user.
func WithUserEmail(email string) UserMonitoringOption {
return func(s Span) {
s.SetTag("usr.email", email)
}
}

// WithUserName returns the option setting the name of the authenticated user.
func WithUserName(name string) UserMonitoringOption {
return func(s Span) {
s.SetTag("usr.name", name)
}
}

// WithUserSessionID returns the option setting the session ID of the authenticated user.
func WithUserSessionID(sessionID string) UserMonitoringOption {
return func(s Span) {
s.SetTag("usr.session_id", sessionID)
}
}

// WithUserRole returns the option setting the role of the authenticated user.
func WithUserRole(role string) UserMonitoringOption {
return func(s Span) {
s.SetTag("usr.role", role)
}
}

// WithUserScope returns the option setting the scope (authorizations) of the authenticated user
func WithUserScope(scope string) UserMonitoringOption {
return func(s Span) {
s.SetTag("usr.scope", scope)
}
}
17 changes: 17 additions & 0 deletions ddtrace/tracer/tracer.go
Expand Up @@ -153,6 +153,23 @@ func Inject(ctx ddtrace.SpanContext, carrier interface{}) error {
return internal.GetGlobalTracer().Inject(ctx, carrier)
}

// SetUser associates user information to the current trace which the
// provided span belongs to. The options can be used to tune which user
// bit of information gets monitored.
func SetUser(s Span, id string, opts ...UserMonitoringOption) {
if s == nil {
return
}
if span, ok := s.(*span); ok && span.context != nil {
span = span.context.trace.root
s = span
}
s.SetTag("usr.id", id)
for _, fn := range opts {
fn(s)
}
}

// payloadQueueSize is the buffer size of the trace channel.
const payloadQueueSize = 1000

Expand Down
41 changes: 41 additions & 0 deletions ddtrace/tracer/tracer_test.go
Expand Up @@ -1694,6 +1694,47 @@ func TestTakeStackTrace(t *testing.T) {
})
}

func TestUserMonitoring(t *testing.T) {
const id = "john.doe#12345"
const name = "John Doe"
const email = "john.doe@hostname.com"
const scope = "read:message, write:files"
const role = "admin"
const sessionID = "session#12345"
expected := []struct{ key, value string }{
{key: "usr.id", value: id},
{key: "usr.name", value: name},
{key: "usr.email", value: email},
{key: "usr.scope", value: scope},
{key: "usr.role", value: role},
{key: "usr.session_id", value: sessionID},
}
tr := newTracer()
defer tr.Stop()

t.Run("root", func(t *testing.T) {
s := tr.newRootSpan("root", "test", "test")
SetUser(s, id, WithUserEmail(email), WithUserName(name), WithUserScope(scope),
WithUserRole(role), WithUserSessionID(sessionID))
s.Finish()
for _, pair := range expected {
assert.Equal(t, pair.value, s.Meta[pair.key])
}
})

t.Run("nested", func(t *testing.T) {
root := tr.newRootSpan("root", "test", "test")
child := tr.newChildSpan("child", root)
SetUser(child, id, WithUserEmail(email), WithUserName(name), WithUserScope(scope),
WithUserRole(role), WithUserSessionID(sessionID))
child.Finish()
root.Finish()
for _, pair := range expected {
assert.Equal(t, pair.value, root.Meta[pair.key])
}
})
}

// BenchmarkTracerStackFrames tests the performance of taking stack trace.
func BenchmarkTracerStackFrames(b *testing.B) {
tracer, _, _, stop := startTestTracer(b, WithSampler(NewRateSampler(0)))
Expand Down
11 changes: 11 additions & 0 deletions internal/appsec/config.go
Expand Up @@ -11,6 +11,8 @@ import (
"os"
"strconv"
"time"
"unicode"
"unicode/utf8"

"gopkg.in/DataDog/dd-trace-go.v1/internal/log"
)
Expand Down Expand Up @@ -69,9 +71,18 @@ func readWAFTimeoutConfig() (timeout time.Duration) {
if value == "" {
return
}

// Check if the value ends with a letter, which means the user has
// specified their own time duration unit(s) such as 1s200ms.
// Otherwise, default to microseconds.
if lastRune, _ := utf8.DecodeLastRuneInString(value); !unicode.IsLetter(lastRune) {
value += "us" // Add the default microsecond time-duration suffix
}

parsed, err := time.ParseDuration(value)
if err != nil {
logEnvVarParsingError(wafTimeoutEnvVar, value, err, timeout)
return
}
if parsed <= 0 {
logUnexpectedEnvVarValue(wafTimeoutEnvVar, parsed, "expecting a strictly positive duration", timeout)
Expand Down
17 changes: 17 additions & 0 deletions internal/appsec/config_test.go
Expand Up @@ -50,6 +50,23 @@ func TestConfig(t *testing.T) {
)
})

t.Run("parsable-default-microsecond", func(t *testing.T) {
restoreEnv := cleanEnv()
defer restoreEnv()
require.NoError(t, os.Setenv(wafTimeoutEnvVar, "1"))
cfg, err := newConfig()
require.NoError(t, err)
require.Equal(
t,
&config{
rules: []byte(staticRecommendedRule),
wafTimeout: 1 * time.Microsecond,
traceRateLimit: defaultTraceRate,
},
cfg,
)
})

t.Run("not-parsable", func(t *testing.T) {
restoreEnv := cleanEnv()
defer restoreEnv()
Expand Down

0 comments on commit 7d80e0f

Please sign in to comment.