* debrand: signoz/SigNoz/SIGNOZ -> o11y/O11y/O11Y across the tree Rename all SigNoz *branding* to O11y in file contents, file/dir names, package names, env vars, config keys, comments, docs, SDK code, and the ClickHouse schema identifiers the querier reads. Collector dependency: - Repoint github.com/hanzoai/signoz-otel-collector -> github.com/hanzoai/otel-collector and bump v0.144.6 -> v0.144.7 (go.mod + go.sum reconciled via go mod tidy). Internal package paths also debranded upstream: signozschemamigrator -> o11yschemamigrator, signozlogspipelineprocessor -> o11ylogspipelineprocessor. - Fix: v0.144.7 dropped otelconst.DistributedFieldKeysTable from the collector's public constants; pin FieldKeysTable = "distributed_field_keys" locally in pkg/telemetrymetadata/tables.go. Package/dir renames (package decl + all importers): pkg/apiserver/signozapiserver -> o11yapiserver, plus signozalertmanager, signozauthzapi, signozglobal, signozquerier, signozruler, and pkg/signoz -> pkg/o11y. Schema (read plane): signoz_traces/metrics/logs/metadata/analytics/meter and signoz_index_v3/index_v2/error_index_v2/spans (+ distributed_*) -> o11y_*. Data-preserving cutover migration added: deploy/clickhouse/migrations/0001_rename_signoz_to_o11y.sql (metadata-only RENAME DATABASE/TABLE, no drop/recreate). Preserved (attribution / external / wire contracts): - LICENSE + NOTICE verbatim (incl. "software from SigNoz", "Copyright ... SigNoz Inc."). - Upstream github.com/SigNoz/* repo URLs + @SigNoz/* CODEOWNERS teams. - Billing resource-attribute regex "signoz.workspace.*" (external wire contract). go build ./pkg/... ./cmd/... = 0; gofmt clean; renamed+schema pkg tests pass. * o11y: bump collector to v0.144.8 (o11y_* physical schema writer) + lockstep deploy plan Collector v0.144.8's schema-migrator + exporters now CREATE/WRITE the same o11y_* physical databases/tables the querier reads and the RENAME migration (0001_rename_signoz_to_o11y.sql) targets. Cross-checked byte-identical: writer DB set == migration target DB set (6); writer prefixed-table set == migration target table set (8); o11y querier reads and cloud reads are subsets of that set. Zero table-name mismatches between writer, readers, and migration. Collector go.mod unchanged between v0.144.7 and v0.144.8 (identical go.mod hash) — pure source rename, no module-graph change. Adds deploy/clickhouse/DEPLOY_signoz_to_o11y_cutover.md: the lockstep order (collector v0.144.8 -> RENAME migration -> o11y+cloud readers) with a fresh/scratch-ClickHouse pre-flight (create via migrator, emit trace+metric, query back) and rollback. Ships together or telemetry blackholes. go build ./pkg/... ./cmd/community = 0.
4.7 KiB
Flagger
Flagger is Hanzo O11y's feature flagging system built on top of the OpenFeature standard. It provides a unified interface for evaluating feature flags across the application, allowing features to be enabled, disabled, or configured dynamically without code changes.
💡 Note: OpenFeature is a CNCF project that provides a vendor-agnostic feature flagging API, making it easy to switch providers without changing application code.
How does it work?
Flagger consists of three main components:
- Registry (
pkg/flagger/registry.go) - Contains all available feature flags with their metadata and default values - Flagger (
pkg/flagger/flagger.go) - The consumer-facing interface for evaluating feature flags - Providers (
pkg/flagger/<provider>flagger/) - Implementations that supply feature flag values (e.g.,configflaggerfor config-based flags)
The evaluation flow works as follows:
- The caller requests a feature flag value via the
Flaggerinterface - Flagger checks the registry to validate the flag exists and get its default value
- Each registered provider is queried for an override value
- If a provider returns a value different from the default, that value is returned
- Otherwise, the default value from the registry is returned
How to add a new feature flag?
1. Register the flag in the registry
Add your feature flag definition in pkg/flagger/registry.go:
var (
// Export the feature name for use in evaluations
FeatureMyNewFeature = featuretypes.MustNewName("my_new_feature")
)
func MustNewRegistry() featuretypes.Registry {
registry, err := featuretypes.NewRegistry(
// ...existing features...
&featuretypes.Feature{
Name: FeatureMyNewFeature,
Kind: featuretypes.KindBoolean, // or KindString, KindFloat, KindInt, KindObject
Stage: featuretypes.StageStable, // or StageAlpha, StageBeta
Description: "Controls whether my new feature is enabled",
DefaultVariant: featuretypes.MustNewName("disabled"),
Variants: featuretypes.NewBooleanVariants(),
},
)
// ...
}
💡 Note: Feature names must match the regex
^[a-z_]+$(lowercase letters and underscores only).
2. Configure the feature flag value (optional)
To override the default value, add an entry in your configuration file:
flagger:
config:
boolean:
my_new_feature: true
Supported configuration types:
| Type | Config Key | Go Type |
|---|---|---|
| Boolean | boolean |
bool |
| String | string |
string |
| Float | float |
float64 |
| Integer | integer |
int64 |
| Object | object |
any |
How to evaluate a feature flag?
Use the Flagger interface to evaluate feature flags. The interface provides typed methods for each value type:
import (
"github.com/Hanzo O11y/o11y/pkg/flagger"
"github.com/Hanzo O11y/o11y/pkg/types/featuretypes"
)
func DoSomething(ctx context.Context, flagger flagger.Flagger) error {
// Create an evaluation context (typically with org ID)
evalCtx := featuretypes.NewFlaggerEvaluationContext(orgID)
// Evaluate with error handling
enabled, err := flagger.Boolean(ctx, flagger.FeatureMyNewFeature, evalCtx)
if err != nil {
return err
}
if enabled {
// Feature is enabled
}
return nil
}
Empty variants
For cases where you want to use a default value on error (and log the error), use the *OrEmpty methods:
func DoSomething(ctx context.Context, flagger flagger.Flagger) {
evalCtx := featuretypes.NewFlaggerEvaluationContext(orgID)
// Returns false on error and logs the error
if flagger.BooleanOrEmpty(ctx, flagger.FeatureMyNewFeature, evalCtx) {
// Feature is enabled
}
}
Available evaluation methods
| Method | Return Type | Empty Variant Default |
|---|---|---|
Boolean() |
(bool, error) |
false |
String() |
(string, error) |
"" |
Float() |
(float64, error) |
0.0 |
Int() |
(int64, error) |
0 |
Object() |
(any, error) |
struct{}{} |
What should I remember?
- Always define feature flags in the registry (
pkg/flagger/registry.go) before using them - Use descriptive feature names that clearly indicate what the flag controls
- Prefer
*OrEmptymethods for non-critical features to avoid error handling overhead - Export feature name variables (e.g.,
FeatureMyNewFeature) for type-safe usage across packages - Consider the feature's lifecycle stage (
Alpha,Beta,Stable) when defining it - Providers are evaluated in order; the first non-default value wins