Skip to content

Commit 98a16f6

Browse files
mrm9084avaniguptaazure-sdkrossgramboCopilot
authored
Azure App Configuration Provider Allocation Id (#40730)
* Revert "Remove Telemetry from main (#37783)" (#37812) This reverts commit a65dfb2. * Allocation Id (#37840) * Adding Telemetry * Telemetry Support * fixing formatting * Update _azureappconfigurationprovider.py * Update _azureappconfigurationproviderasync.py * formatting * changing doc style due to pylint-next * fixing kwargs docs * Formatting * Review comments * Changed label checking. * black format changes * pylint * Update sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_azureappconfigurationprovider.py Co-authored-by: Avani Gupta <[email protected]> * added space checks * Update conftest.py * moved telemetry to client wrapper * fixing format * updating after merge * fixing black issue * removing unused imports * AllocationId * Update CODEOWNERS * Update CODEOWNERS * fixing issues * Update _client_manager_base.py * Fixing configuration value empty in calc * fixing pylint * Update _constants.py * review comments * fixing allocation check * format fix --------- Co-authored-by: Avani Gupta <[email protected]> * Python Provider 2.0.0b2 Changelog update (#37860) * Update CHANGELOG.md * Update CHANGELOG.md * Increment package version after release of azure-appconfiguration-provider (#37877) * Update _client_manager_base.py (#38019) * App Config Allocation Id Update (#38065) * updated calc to sort keys * Update CHANGELOG.md * Allocation id update (#38242) * updated calc to sort keys * Update CHANGELOG.md * Update _client_manager_base.py * Update CHANGELOG.md (#38521) * Increment package version after release of azure-appconfiguration-provider (#38553) * fixing imports * Updating Version and Changelog * Update _client_manager_base.py * Increment package version after release of azure-appconfiguration-provider (#40470) * Updating for release * Update CHANGELOG.md * Update sdk/appconfiguration/azure-appconfiguration-provider/CHANGELOG.md Co-authored-by: Ross Grambo <[email protected]> * Update sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_client_manager_base.py Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Avani Gupta <[email protected]> Co-authored-by: Azure SDK Bot <[email protected]> Co-authored-by: Ross Grambo <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent c202be6 commit 98a16f6

File tree

4 files changed

+100
-5
lines changed

4 files changed

+100
-5
lines changed

sdk/appconfiguration/azure-appconfiguration-provider/CHANGELOG.md

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
# Release History
22

3-
## 2.0.3 (Unreleased)
3+
## 2.1.0 (2025-04-28)
44

55
### Features Added
66

7-
### Breaking Changes
7+
* Added AllocationId to the feature flag telemetry metadata when the feature flag has telemetry enabled.
8+
9+
## 2.1.0b1 (2025-04-10)
810

911
### Bugs Fixed
1012

11-
### Other Changes
13+
* Updates the feature flag telemetry to use the provided endpoint instead of the endpoint of the store the feature flag was loaded from.
14+
* Removes FeatureFlagId from feature flag telemetry.
1215

1316
## 2.0.2 (2025-04-17)
1417

1518
### Other Changes
1619

1720
* Updates telemetry for JSON usage.
21+
1822
## 2.0.1 (2025-03-07)
1923

2024
### Bugs Fixed

sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_client_manager_base.py

+91-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
# Licensed under the MIT License. See License.txt in the project root for
44
# license information.
55
# -------------------------------------------------------------------------
6+
import json
67
import random
8+
import base64
9+
import hashlib
710
from dataclasses import dataclass
8-
from typing import Dict, Mapping, Any, Optional
11+
from typing import Dict, List, Optional, Mapping, Any
912
from azure.appconfiguration import ( # type:ignore # pylint:disable=no-name-in-module
1013
FeatureFlagConfigurationSetting,
1114
)
@@ -21,6 +24,7 @@
2124
METADATA_KEY,
2225
ETAG_KEY,
2326
FEATURE_FLAG_REFERENCE_KEY,
27+
ALLOCATION_ID_KEY,
2428
)
2529

2630
FALLBACK_CLIENT_REFRESH_EXPIRED_INTERVAL = 3600 # 1 hour in seconds
@@ -33,6 +37,89 @@
3337
class _ConfigurationClientWrapperBase:
3438
endpoint: str
3539

40+
@staticmethod
41+
def _generate_allocation_id(feature_flag_value: Dict[str, JSON]) -> Optional[str]:
42+
"""
43+
Generates an allocation ID for the specified feature.
44+
seed=123abc\ndefault_when_enabled=Control\npercentiles=0,Control,20;20,Test,100\nvariants=Control,standard;Test,special # pylint:disable=line-too-long
45+
46+
:param Dict[str, JSON] feature_flag_value: The feature to generate an allocation ID for.
47+
:rtype: str
48+
:return: The allocation ID.
49+
"""
50+
51+
allocation_id = ""
52+
allocated_variants = []
53+
54+
allocation: Optional[JSON] = feature_flag_value.get("allocation")
55+
56+
if not allocation:
57+
return None
58+
59+
# Seed
60+
allocation_id = f"seed={allocation.get('seed', '')}"
61+
62+
# DefaultWhenEnabled
63+
if "default_when_enabled" in allocation:
64+
allocated_variants.append(allocation.get("default_when_enabled"))
65+
66+
allocation_id += f"\ndefault_when_enabled={allocation.get('default_when_enabled', '')}"
67+
68+
# Percentile
69+
allocation_id += "\npercentiles="
70+
71+
percentile = allocation.get("percentile")
72+
73+
if percentile:
74+
percentile_allocations = sorted(
75+
(x for x in percentile if x.get("from") != x.get("to")),
76+
key=lambda x: x.get("from"),
77+
)
78+
79+
for percentile_allocation in percentile_allocations:
80+
if "variant" in percentile_allocation:
81+
allocated_variants.append(percentile_allocation.get("variant"))
82+
83+
allocation_id += ";".join(
84+
f"{pa.get('from')}," f"{base64.b64encode(pa.get('variant').encode()).decode()}," f"{pa.get('to')}"
85+
for pa in percentile_allocations
86+
)
87+
88+
if not allocated_variants and not allocation.get("seed"):
89+
return None
90+
91+
# Variants
92+
allocation_id += "\nvariants="
93+
94+
variants_value = feature_flag_value.get("variants")
95+
if variants_value and (isinstance(variants_value, list) or all(isinstance(v, dict) for v in variants_value)):
96+
if (
97+
allocated_variants
98+
and isinstance(variants_value, list)
99+
and all(isinstance(v, dict) for v in variants_value)
100+
):
101+
sorted_variants: List[Dict[str, Any]] = sorted(
102+
(v for v in variants_value if v.get("name") in allocated_variants),
103+
key=lambda v: v.get("name"),
104+
)
105+
106+
for v in sorted_variants:
107+
allocation_id += f"{base64.b64encode(v.get('name', '').encode()).decode()},"
108+
if "configuration_value" in v:
109+
allocation_id += (
110+
f"{json.dumps(v.get('configuration_value', ''), separators=(',', ':'), sort_keys=True)}"
111+
)
112+
allocation_id += ";"
113+
if sorted_variants:
114+
allocation_id = allocation_id[:-1]
115+
116+
# Create a sha256 hash of the allocation_id
117+
hash_object = hashlib.sha256(allocation_id.encode())
118+
hash_digest = hash_object.digest()
119+
120+
# Encode the first 15 bytes in base64 url
121+
return base64.urlsafe_b64encode(hash_digest[:15]).decode()
122+
36123
def _feature_flag_telemetry(
37124
self, endpoint: str, feature_flag: FeatureFlagConfigurationSetting, feature_flag_value: Dict
38125
):
@@ -48,6 +135,9 @@ def _feature_flag_telemetry(
48135
feature_flag_reference += f"?label={feature_flag.label}"
49136
if feature_flag_value[TELEMETRY_KEY].get("enabled"):
50137
feature_flag_value[TELEMETRY_KEY][METADATA_KEY][FEATURE_FLAG_REFERENCE_KEY] = feature_flag_reference
138+
allocation_id = self._generate_allocation_id(feature_flag_value)
139+
if allocation_id:
140+
feature_flag_value[TELEMETRY_KEY][METADATA_KEY][ALLOCATION_ID_KEY] = allocation_id
51141

52142
def _feature_flag_appconfig_telemetry(
53143
self, feature_flag: FeatureFlagConfigurationSetting, filters_used: Dict[str, bool]

sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_constants.py

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
TELEMETRY_KEY = "telemetry"
2121
METADATA_KEY = "metadata"
2222

23+
ALLOCATION_ID_KEY = "AllocationId"
2324
ETAG_KEY = "ETag"
2425
FEATURE_FLAG_REFERENCE_KEY = "FeatureFlagReference"
2526

sdk/appconfiguration/azure-appconfiguration-provider/azure/appconfiguration/provider/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
# license information.
55
# -------------------------------------------------------------------------
66

7-
VERSION = "2.0.3"
7+
VERSION = "2.1.0"

0 commit comments

Comments
 (0)