Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RUMM-886 setUserInfo(..., extraInfo) added #315

Merged
merged 2 commits into from Nov 26, 2020

Conversation

buranmert
Copy link
Contributor

@buranmert buranmert commented Nov 20, 2020

What and why?

Datadog.UserInfo has arbitrary attributes via extraInfo

How?

UserInfoProvider keeps extraInfo dictionary along with userInfo
Features (Logs, APM and RUM) encode extraInfo according to their own rules

Logs:

extraInfo: ["key": "value"] -> "usr.key: value"

APM:

extraInfo: ["key": "value"] -> "meta.usr.key: value"

RUM:

extraInfo: ["key": "value"] -> "context.usr.key: value"

Discussion 💭

In this PR, I put usr. prefix to extraInfo within UserInfoProvider and pass it to features as regular attributes.
But UserInfoProvider passes UserInfo value without encoding and the features (LogEncoder and SpanEncoder) are responsible for its encoding.
This is some sort of inconsistency in UserInfoProvider, I didn't like that ❌

Can't we make UserInfo: Encodable to de-duplicate its encoding logic?

Review checklist

  • Feature or bugfix MUST have appropriate tests (unit, integration)
  • Make sure each commit and the PR mention the Issue number or JIRA reference

@buranmert buranmert added this to the next-version milestone Nov 20, 2020
@buranmert buranmert self-assigned this Nov 20, 2020
@ncreated
Copy link
Collaborator

In this PR, I put usr. prefix to extraInfo within UserInfoProvider and pass it to features as regular attributes.
But UserInfoProvider passes UserInfo value without encoding and the features (LogEncoder and SpanEncoder) are responsible for its encoding.
This is some sort of inconsistency in UserInfoProvider, I didn't like that ❌

What exactly is inconsistent?

UserInfoProvider provides the UserInfo model and each feature decides on its own, how to encode it:

  • Logging feature puts them at the root level of the log JSON: usr.id, usr.name, usr.email,
  • Tracing feature nests them under meta object in the span JSON: meta.usr.id, meta.usr.name, meta.usr.email,
  • RUM feature uses auto-generated RUMDataUSR model to encode it according to rum-events-format.

Having single struct UserInfo: Encodable would be a wrong abstraction, as each feature needs to decide by its own.

In this PR, I put usr. prefix to extraInfo within UserInfoProvider

In all other places (see: NetworkConnectionInfoProvider, CarrierInfoProvider, UserInfoProvider) the encoding keys of custom data are decided by the encoder (LogEncoder, SpanEncoder). Creating user attribute keys at the beginning of data flow leaks this abstraction. I don't see any benefit of this approach, why do you think it's better?

@buranmert buranmert force-pushed the buranmert/RUMM-886-user-extraInfo branch from ce3ada5 to 78cff21 Compare November 25, 2020 10:59
@buranmert buranmert force-pushed the buranmert/RUMM-886-user-extraInfo branch from 78cff21 to 61246f6 Compare November 25, 2020 18:34
@buranmert buranmert marked this pull request as ready for review November 25, 2020 18:35
@buranmert buranmert requested a review from a team as a code owner November 25, 2020 18:35
Copy link
Collaborator

@ncreated ncreated left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very good 👌, but needs the fix for Tracing.

@@ -78,9 +78,15 @@ public class Datadog {
public static func setUserInfo(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This public API is missing the comment.

@@ -198,5 +198,8 @@ internal struct SpanEncoder {
let metaKey = "meta.\($0.key)"
try container.encode($0.value, forKey: DynamicCodingKey(metaKey))
}
try span.userInfo.extraInfo.forEach {
try container.encode(EncodableValue($1), forKey: DynamicCodingKey("meta.usr.\($0)"))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This leads to all spans being rejected by Intake if the user extra attribute is not String, e.g.:

Datadog.setUserInfo(
    id: "abcd-1234",
    name: "foo",
    email: "foo@example.com",
    extraInfo: [
        "is-registered": true
    ]
)

As stated in this method comment:

// NOTE: RUMM-299 only string values are supported for `meta.*` attributes

Whatever we encode on meta.* key must be serialised to String representation. We should use JSONStringEncodableValue in SpanBuilder as it is done for span.tags.

id: "abc-123",
name: "Foo",
email: "foo@bar.com",
extraInfo: ["extra_key": "extra_value"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because extraInfo encoding depends on the feature (Logging and RUM supports multiple Encodable types, but Tracing encodes all values as String), it seems better to mix few types in this test:

extraInfo: ["extra_string": "string_value", "extra_int": 42, "extra_bool": true]

and document the expected encoding result in test assertions.

@@ -335,8 +335,8 @@ class TracerTests: XCTestCase {
Datadog.setUserInfo(id: "abc-123", name: "Foo")
tracer.startSpan(operationName: "span with user `id` and `name`").finish()

Datadog.setUserInfo(id: "abc-123", name: "Foo", email: "foo@example.com")
tracer.startSpan(operationName: "span with user `id`, `name` and `email`").finish()
Datadog.setUserInfo(id: "abc-123", name: "Foo", email: "foo@example.com", extraInfo: ["extra_key": "extra_value"])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because extraInfo encoding depends on the feature (Logging and RUM supports multiple Encodable types, but Tracing encodes all values as String), it seems better to mix few types in this test:

extraInfo: ["extra_string": "string_value", "extra_int": 42, "extra_bool": true]

and document the expected encoding result in test assertions.

@@ -186,16 +186,16 @@ class LoggerTests: XCTestCase {
Datadog.setUserInfo(id: "abc-123", name: "Foo")
logger.debug("message with user `id` and `name`")

Datadog.setUserInfo(id: "abc-123", name: "Foo", email: "foo@example.com")
logger.debug("message with user `id`, `name` and `email`")
Datadog.setUserInfo(id: "abc-123", name: "Foo", email: "foo@example.com", extraInfo: ["extra_key": "extra_value"])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because extraInfo encoding depends on the feature (Logging and RUM supports multiple Encodable types, but Tracing encodes all values as String), it seems better to mix few types in this test:

extraInfo: ["extra_string": "string_value", "extra_int": 42, "extra_bool": true]

and document the expected encoding result in test assertions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i can't pass different types in a dict to assertUserInfo method below
i will need to use matcher.assertValue(forKey:value:)

@buranmert buranmert force-pushed the buranmert/RUMM-886-user-extraInfo branch from 482a35c to daa2209 Compare November 26, 2020 14:32
@buranmert buranmert force-pushed the buranmert/RUMM-886-user-extraInfo branch from daa2209 to 72a19f2 Compare November 26, 2020 14:50
Copy link
Collaborator

@ncreated ncreated left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good 🚀

@buranmert buranmert merged commit 50e3d79 into master Nov 26, 2020
@buranmert buranmert deleted the buranmert/RUMM-886-user-extraInfo branch November 26, 2020 16:10
@ncreated ncreated removed this from the next-version milestone Dec 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants