Skip to content

feat: Add feature flag models and buffers#8078

Open
denrase wants to merge 18 commits into
mainfrom
feat/feature-flag-models-and-buffer
Open

feat: Add feature flag models and buffers#8078
denrase wants to merge 18 commits into
mainfrom
feat/feature-flag-models-and-buffer

Conversation

@denrase

@denrase denrase commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

#skip-changelog

📜 Description

Adds shared feature flag models, buffer storage, and serialization support for feature flag evaluations.

This includes:

  • API support for adding and removing feature flags (internal only for now)
  • Feature flag evaluation/value models
  • Scope and span feature flag storage
    • Limits and buffer overflow behaviour
    • Scope serialization into the flags context
    • Span/transaction serialization into flag.evaluation.* data

The implementation intentionally minimizes Objective-C exposure. The feature flag models and buffer logic live in Swift, while Objective-C only keeps a private SentryFeatureFlagStorage reference on scope/span internals so existing ObjC serialization paths can include the data.

The API mirrors the metrics-style design by accepting typed feature flag values through an internal value abstraction, allowing us to support additional result types beyond booleans in the future without changing the storage and serialization model.

💡 Motivation and Context

Adds the shared model and buffering layer for feature flag evaluations.

Closes #7988

💚 How did you test it?

Added targeted tests.

📝 Checklist

You have to check all boxes before merging:

  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.
  • If I added a new public API, I also added it to the SentryObjC wrapper.

denrase added 7 commits June 2, 2026 15:45
Introduces the internal foundation for feature flag evaluation tracking.

The implementation adds a shared feature flag value/evaluation model plus dedicated buffers for scope and span storage. Scope storage keeps the latest unique evaluations up to the configured internal limit and evicts the oldest entry on overflow. Span storage has its own smaller per-span limit and rejects new flag names once full while still allowing updates to existing flags.

This also wires the private storage into scope lifecycle behavior:
- scope cloning copies feature flags without sharing future mutations
- `clear()` clears feature flags
- scope serialization includes the stored flag context
- span internals can store and serialize feature flag evaluations as span data

No public feature flag API is added in this PR; this is the private storage layer that later API and integration work will build on.
@denrase denrase changed the title feat: add feature flag models and buffers feat: Add feature flag models and buffers Jun 16, 2026
@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor
Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against 11ee533

@denrase denrase marked this pull request as ready for review June 16, 2026 15:12
@denrase denrase added the ready-to-merge Use this label to trigger all PR workflows label Jun 16, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5614a54. Configure here.

Comment thread Sources/Sentry/SentryScope.m
@sentry

sentry Bot commented Jun 16, 2026

Copy link
Copy Markdown

📲 Install Builds

iOS

🔗 App Name App ID Version Configuration
SDK-Size io.sentry.sample.SDK-Size 9.18.0 (1) Release

⚙️ sentry-cocoa Build Distribution Settings

@github-actions

Copy link
Copy Markdown
Contributor

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1219.87 ms 1253.80 ms 33.93 ms
Size 24.14 KiB 1.19 MiB 1.17 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
9b154ad 1218.94 ms 1253.60 ms 34.66 ms
ce900e7 1212.40 ms 1244.57 ms 32.18 ms
48fa69f 1221.60 ms 1251.52 ms 29.92 ms
67ea138 1212.54 ms 1240.48 ms 27.94 ms
d1ddc41 1236.42 ms 1267.21 ms 30.79 ms
1770336 1225.09 ms 1251.32 ms 26.23 ms
eddca8a 1226.17 ms 1259.98 ms 33.81 ms
d6af355 1214.83 ms 1252.78 ms 37.95 ms
92bcc8f 1233.43 ms 1270.20 ms 36.77 ms
bf10fe6 1226.00 ms 1260.76 ms 34.76 ms

App size

Revision Plain With Sentry Diff
9b154ad 24.14 KiB 1.16 MiB 1.13 MiB
ce900e7 24.14 KiB 1.15 MiB 1.13 MiB
48fa69f 24.14 KiB 1.15 MiB 1.13 MiB
67ea138 24.14 KiB 1.17 MiB 1.15 MiB
d1ddc41 24.14 KiB 1.17 MiB 1.15 MiB
1770336 24.14 KiB 1.15 MiB 1.13 MiB
eddca8a 24.14 KiB 1.15 MiB 1.13 MiB
d6af355 24.14 KiB 1.18 MiB 1.15 MiB
92bcc8f 24.14 KiB 1.15 MiB 1.13 MiB
bf10fe6 24.14 KiB 1.17 MiB 1.15 MiB

@philprime philprime left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM with comments to consider

// swiftlint:disable missing_docs
import Foundation

final class SentryFeatureFlagBuffer {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

m: Can we use a struct here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I’d keep this as a class since it owns mutable state and handles its own locking. If this was a struct we’d still need a synchronized wrapper around it from both swift and objc, as i don't want to do syncing from every call site.

Comment thread Sources/Swift/FeatureFlags/SentryFeatureFlagStore.swift Outdated
Comment thread Sources/Swift/FeatureFlags/SentryFeatureFlagStore.swift Outdated
Comment thread Sources/Sentry/SentrySpanInternal.m Outdated
@denrase denrase self-assigned this Jun 17, 2026

@NinjaLikesCheez NinjaLikesCheez left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM - a few comments to consider

Comment thread Sources/Swift/FeatureFlags/SentryFeatureFlagBuffer.swift
guard maxSize > 0 else {
return
}
let evaluation = SentryFeatureFlagEvaluation(flag: name, result: value.asSentryFeatureFlagValue)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

m: since flag is effectively used as a key, a Set or Dictionary may be a more effective storage. This would simplify the lookup and replacement logic and reduce the runtime complexity.

Ofc, this breaks .dropOldest ideally I'd recommend [OrderedSet])(https://github.com/apple/swift-collections/blob/main/Sources/OrderedCollections/OrderedSet/OrderedSet.swift) but since we can't pull in dependencies easily, we could wrap the evaluation in another object that holds the insertion date. Then we only hit the O(n) path if we need to remove the oldest evaluation.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Since payload order matters, I kept the ordered array as the source of truth and added a [String: Int] lookup map. This avoids sorting during allEvaluations/serialization, which happens on the event/span serialization path, while still making keyed lookup/update cheap.

The only remaining O(n) paths are the ones that actually shift or reorder the array, which should be fine for max sizes 100/10. They are also not worse than before.

Comment thread Sources/Sentry/SentrySpanInternal.m Outdated
Comment thread Sources/Swift/FeatureFlags/SentryFeatureFlagBuffer.swift Outdated
Comment thread Sources/Swift/FeatureFlags/SentryFeatureFlagEvaluation.swift Outdated
Comment thread Sources/Swift/FeatureFlags/SentryFeatureFlagEvaluation.swift Outdated
Comment thread Sources/Sentry/SentryScope.m
@denrase denrase requested a review from NinjaLikesCheez June 22, 2026 11:33
@denrase denrase enabled auto-merge (squash) June 22, 2026 11:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Use this label to trigger all PR workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Shared Model and Buffers

3 participants