Skip to content

Conversation

KevinFairise2
Copy link
Member

@KevinFairise2 KevinFairise2 commented Oct 14, 2025

Introduce Feature Flag support inside dda commands.

Mostly solve the problems described in: https://datadoghq.atlassian.net/wiki/spaces/~7120201870126a495245b69e47156354de0ad9/pages/5569413152/Feature+Flags+dda?atlOrigin=eyJpIjoiZWI5Y2NjNTRhMDViNDc3NmFkYWNlNGVmOGExMjkzY2QiLCJwIjoiYyJ9

In that PR feature flags are only supported when running command locally.
A client token is required and will be fetched using the same mechanism as for the telemetry API key.

The feature flag can be used easily inside the application code by calling
app.features.enabled("flag", "default_value", extra_context)
The extra context is not needed, by default the context is populated here and contains info about whether this is a CI run, and the username if it exists

@KevinFairise2 KevinFairise2 force-pushed the kfairise/feature-flags-dda branch 10 times, most recently from 3d4fc3a to e09b016 Compare October 14, 2025 12:09
@KevinFairise2 KevinFairise2 force-pushed the kfairise/feature-flags-dda branch from e09b016 to 826b998 Compare October 14, 2025 12:12
@KevinFairise2 KevinFairise2 marked this pull request as ready for review October 14, 2025 12:15
@KevinFairise2 KevinFairise2 requested a review from a team as a code owner October 14, 2025 12:15
Copy link
Contributor

@ofek ofek left a comment

Choose a reason for hiding this comment

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

Took a first pass, looking good so far!

@ofek ofek changed the title Support Datadog feauture flags Support Datadog feature flags Oct 14, 2025
@KevinFairise2 KevinFairise2 force-pushed the kfairise/feature-flags-dda branch 6 times, most recently from a9c82ad to 3315e9c Compare October 15, 2025 13:56
@KevinFairise2 KevinFairise2 requested a review from ofek October 15, 2025 14:16
@KevinFairise2 KevinFairise2 force-pushed the kfairise/feature-flags-dda branch from 3315e9c to d0ef55f Compare October 15, 2025 15:27
Copy link
Contributor

@ofek ofek left a comment

Choose a reason for hiding this comment

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

I think this is my final pass, thanks a lot!

@KevinFairise2 KevinFairise2 force-pushed the kfairise/feature-flags-dda branch 3 times, most recently from 6b8fd15 to 536a5fc Compare October 16, 2025 08:56
@KevinFairise2 KevinFairise2 force-pushed the kfairise/feature-flags-dda branch from 536a5fc to d7a0c79 Compare October 16, 2025 09:00
@KevinFairise2 KevinFairise2 requested a review from ofek October 16, 2025 09:09
@KevinFairise2 KevinFairise2 force-pushed the kfairise/feature-flags-dda branch from 2165e46 to e0fc87d Compare October 17, 2025 12:17
VERBOSE = "DDA_VERBOSE"
NO_DYNAMIC_DEPS = "DDA_NO_DYNAMIC_DEPS"
TELEMETRY_API_KEY = "DDA_TELEMETRY_API_KEY"
FEATURE_FLAGS_CLIENT_TOKEN = "DDA_FEATURE_FLAGS_CLIENT_TOKEN" # noqa: S105 This is not a hardcoded secret but the linter complains on it
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
FEATURE_FLAGS_CLIENT_TOKEN = "DDA_FEATURE_FLAGS_CLIENT_TOKEN" # noqa: S105 This is not a hardcoded secret but the linter complains on it
FEATURE_FLAGS_CLIENT_TOKEN = "DDA_FEATURE_FLAGS_CLIENT_TOKEN" # noqa: S105

import json
from typing import TYPE_CHECKING, Any

from httpx import HTTPError
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be lazily imported where it's required.

Comment on lines +56 to +58
}

headers["dd-application-id"] = self.__app_id
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
}
headers["dd-application-id"] = self.__app_id
"dd-application-id": self.__app_id,
}

self.__cache: dict[tuple[str, str, tuple[tuple[str, str], ...]], Any] = {}

@cached_property
def __client_token(self) -> str | None:
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is only used by the client and it feels odd to instantiate the client with potentially no token, requiring the client to check how it was constructed. Can we change this property to create and return a client or None if we can't get a token?

if isinstance(value, str):
stringified_attributes[key] = value
else:
stringified_attributes[key] = json.dumps(value)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this is desirable. Can we just rely on the backend rejecting bad data?

>>> import json
>>> json.dumps(0)
'0'
>>> json.dumps(None)
'null'

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.

2 participants