toggly 0.2.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +57 -0
- data/README.md +34 -2
- data/lib/toggly/client/cache_telemetry.rb +36 -0
- data/lib/toggly/client/snapshot_support.rb +38 -0
- data/lib/toggly/client.rb +173 -51
- data/lib/toggly/config.rb +39 -1
- data/lib/toggly/context.rb +135 -9
- data/lib/toggly/definition_cache.rb +78 -0
- data/lib/toggly/definitions_provider.rb +72 -18
- data/lib/toggly/evaluation_engine.rb +4 -3
- data/lib/toggly/evaluators/always_off.rb +5 -1
- data/lib/toggly/evaluators/always_on.rb +5 -1
- data/lib/toggly/evaluators/base.rb +21 -3
- data/lib/toggly/evaluators/browser_family.rb +27 -0
- data/lib/toggly/evaluators/browser_language.rb +26 -0
- data/lib/toggly/evaluators/context_property.rb +5 -1
- data/lib/toggly/evaluators/contextual_targeting.rb +4 -0
- data/lib/toggly/evaluators/country.rb +30 -0
- data/lib/toggly/evaluators/device_type.rb +27 -0
- data/lib/toggly/evaluators/operating_system.rb +31 -0
- data/lib/toggly/evaluators/percentage.rb +11 -49
- data/lib/toggly/evaluators/segment_helpers.rb +98 -0
- data/lib/toggly/evaluators/targeting.rb +61 -14
- data/lib/toggly/evaluators/time_window.rb +14 -9
- data/lib/toggly/evaluators/user_claims.rb +27 -0
- data/lib/toggly/feature_definition.rb +1 -2
- data/lib/toggly/http_request_mapper.rb +64 -0
- data/lib/toggly/registry.rb +25 -6
- data/lib/toggly/request_context.rb +77 -0
- data/lib/toggly/sticky_hash.rb +39 -0
- data/lib/toggly/telemetry/grpc_clients.rb +333 -0
- data/lib/toggly/telemetry/metrics_batcher.rb +140 -0
- data/lib/toggly/telemetry/pb/metrics_pb.rb +28 -0
- data/lib/toggly/telemetry/pb/metrics_services_pb.rb +28 -0
- data/lib/toggly/telemetry/pb/usage_pb.rb +27 -0
- data/lib/toggly/telemetry/pb/usage_services_pb.rb +28 -0
- data/lib/toggly/telemetry/runtime.rb +262 -0
- data/lib/toggly/telemetry/runtime_flush.rb +89 -0
- data/lib/toggly/telemetry/usage_batcher.rb +277 -0
- data/lib/toggly/telemetry.rb +37 -0
- data/lib/toggly/user_agent_parser.rb +69 -0
- data/lib/toggly/version.rb +1 -1
- data/lib/toggly.rb +16 -1
- data/proto/metrics.proto +60 -0
- data/proto/usage.proto +55 -0
- metadata +29 -3
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Toggly
|
|
4
|
+
# Best-effort User-Agent parse result for segment filters.
|
|
5
|
+
class ParsedUserAgent
|
|
6
|
+
# @return [String]
|
|
7
|
+
attr_reader :browser_family, :os_family, :device_family
|
|
8
|
+
|
|
9
|
+
def initialize(browser_family:, os_family:, device_family:)
|
|
10
|
+
@browser_family = browser_family
|
|
11
|
+
@os_family = os_family
|
|
12
|
+
@device_family = device_family
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Best-effort UA parsing (parity with toggly-eval / Java / Python).
|
|
17
|
+
module UserAgentParser
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
# @param user_agent [String, nil]
|
|
21
|
+
# @return [ParsedUserAgent, nil]
|
|
22
|
+
def parse(user_agent)
|
|
23
|
+
return nil if user_agent.nil? || user_agent.empty?
|
|
24
|
+
|
|
25
|
+
ParsedUserAgent.new(
|
|
26
|
+
browser_family: detect_browser(user_agent),
|
|
27
|
+
os_family: detect_os(user_agent),
|
|
28
|
+
device_family: detect_device(user_agent)
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def detect_browser(user_agent)
|
|
33
|
+
return "Edge" if user_agent.include?("Edg/") || user_agent.include?("EdgiOS/")
|
|
34
|
+
return "Opera" if user_agent.include?("OPR/") || user_agent.include?("Opera")
|
|
35
|
+
return "Chrome" if user_agent.include?("Chrome/") || user_agent.include?("CriOS/")
|
|
36
|
+
return "Firefox" if user_agent.include?("Firefox/") || user_agent.include?("FxiOS/")
|
|
37
|
+
if user_agent.include?("Safari/") && user_agent.include?("Version/") &&
|
|
38
|
+
!user_agent.include?("Chrome") && !user_agent.include?("Chromium")
|
|
39
|
+
return "Safari"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
"Other"
|
|
43
|
+
end
|
|
44
|
+
module_function :detect_browser
|
|
45
|
+
|
|
46
|
+
def detect_os(user_agent)
|
|
47
|
+
return "Android" if user_agent.include?("Android")
|
|
48
|
+
if user_agent.include?("iPhone") || user_agent.include?("iPad") || user_agent.include?("iPod") ||
|
|
49
|
+
user_agent.include?("CPU iPhone OS") || user_agent.include?("CPU OS")
|
|
50
|
+
return "iOS"
|
|
51
|
+
end
|
|
52
|
+
return "Mac OS" if user_agent.include?("Mac OS X") || user_agent.include?("Macintosh")
|
|
53
|
+
return "Windows" if user_agent.include?("Windows")
|
|
54
|
+
return "Linux" if user_agent.include?("Linux")
|
|
55
|
+
|
|
56
|
+
"Other"
|
|
57
|
+
end
|
|
58
|
+
module_function :detect_os
|
|
59
|
+
|
|
60
|
+
def detect_device(user_agent)
|
|
61
|
+
return "iPhone" if user_agent.include?("iPhone")
|
|
62
|
+
return "iPad" if user_agent.include?("iPad")
|
|
63
|
+
return "iPod" if user_agent.include?("iPod")
|
|
64
|
+
|
|
65
|
+
"Other"
|
|
66
|
+
end
|
|
67
|
+
module_function :detect_device
|
|
68
|
+
end
|
|
69
|
+
end
|
data/lib/toggly/version.rb
CHANGED
data/lib/toggly.rb
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "toggly/version"
|
|
4
|
+
require_relative "toggly/telemetry"
|
|
4
5
|
require_relative "toggly/config"
|
|
6
|
+
require_relative "toggly/request_context"
|
|
7
|
+
require_relative "toggly/http_request_mapper"
|
|
8
|
+
require_relative "toggly/sticky_hash"
|
|
9
|
+
require_relative "toggly/user_agent_parser"
|
|
5
10
|
require_relative "toggly/context"
|
|
6
11
|
require_relative "toggly/errors"
|
|
7
12
|
require_relative "toggly/feature_definition"
|
|
8
13
|
require_relative "toggly/evaluators/base"
|
|
14
|
+
require_relative "toggly/evaluators/segment_helpers"
|
|
9
15
|
require_relative "toggly/evaluators/always_on"
|
|
10
16
|
require_relative "toggly/evaluators/always_off"
|
|
11
17
|
require_relative "toggly/evaluators/percentage"
|
|
@@ -13,12 +19,19 @@ require_relative "toggly/evaluators/targeting"
|
|
|
13
19
|
require_relative "toggly/evaluators/time_window"
|
|
14
20
|
require_relative "toggly/evaluators/contextual_targeting"
|
|
15
21
|
require_relative "toggly/evaluators/context_property"
|
|
22
|
+
require_relative "toggly/evaluators/browser_family"
|
|
23
|
+
require_relative "toggly/evaluators/browser_language"
|
|
24
|
+
require_relative "toggly/evaluators/country"
|
|
25
|
+
require_relative "toggly/evaluators/device_type"
|
|
26
|
+
require_relative "toggly/evaluators/operating_system"
|
|
27
|
+
require_relative "toggly/evaluators/user_claims"
|
|
16
28
|
require_relative "toggly/entity_context"
|
|
17
29
|
require_relative "toggly/registry"
|
|
18
30
|
require_relative "toggly/evaluation_engine"
|
|
19
31
|
require_relative "toggly/snapshot_providers/base"
|
|
20
32
|
require_relative "toggly/snapshot_providers/memory"
|
|
21
33
|
require_relative "toggly/snapshot_providers/file"
|
|
34
|
+
require_relative "toggly/definition_cache"
|
|
22
35
|
require_relative "toggly/definitions_provider"
|
|
23
36
|
require_relative "toggly/client"
|
|
24
37
|
|
|
@@ -38,7 +51,9 @@ require_relative "toggly/client"
|
|
|
38
51
|
# context = Toggly::Context.new(
|
|
39
52
|
# identity: "user-123",
|
|
40
53
|
# groups: ["beta-testers"],
|
|
41
|
-
#
|
|
54
|
+
# claims: { "role" => "admin" },
|
|
55
|
+
# request: Toggly::RequestContext.new(country: "US"),
|
|
56
|
+
# traits: { plan: "enterprise" }
|
|
42
57
|
# )
|
|
43
58
|
#
|
|
44
59
|
# if client.enabled?("premium-feature", context: context)
|
data/proto/metrics.proto
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package Metrics;
|
|
4
|
+
|
|
5
|
+
option go_package = "github.com/ops-ai/Toggly.FeatureManagement/toggly-go/toggly/metrics/metricspb";
|
|
6
|
+
|
|
7
|
+
import "google/protobuf/timestamp.proto";
|
|
8
|
+
|
|
9
|
+
message MetricStat {
|
|
10
|
+
string appKey = 1;
|
|
11
|
+
string environment = 2;
|
|
12
|
+
google.protobuf.Timestamp time = 3;
|
|
13
|
+
repeated MetricStatMessage stats = 4;
|
|
14
|
+
repeated MetricCounterMessage counters = 5;
|
|
15
|
+
repeated MetricObservationMessage observations = 6;
|
|
16
|
+
optional string instanceName = 7;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
message MetricStatMessage {
|
|
20
|
+
string metric = 1;
|
|
21
|
+
int32 enabledCount = 2 [deprecated = true];
|
|
22
|
+
int32 disabledCount = 3 [deprecated = true];
|
|
23
|
+
optional string feature = 4;
|
|
24
|
+
double value = 5 [deprecated = true];
|
|
25
|
+
optional double valueDisabled = 6 [deprecated = true];
|
|
26
|
+
|
|
27
|
+
// Multi-variate support - Key: variant name (e.g., "enabled", "control")
|
|
28
|
+
map<string, double> variantValues = 7;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
message MetricCounterMessage {
|
|
32
|
+
string metric = 1;
|
|
33
|
+
int32 enabledCount = 2 [deprecated = true];
|
|
34
|
+
int32 disabledCount = 3 [deprecated = true];
|
|
35
|
+
optional string feature = 4;
|
|
36
|
+
double value = 5 [deprecated = true];
|
|
37
|
+
optional double valueDisabled = 6 [deprecated = true];
|
|
38
|
+
|
|
39
|
+
map<string, double> variantValues = 7;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
message MetricObservationMessage {
|
|
43
|
+
google.protobuf.Timestamp time = 1;
|
|
44
|
+
string metric = 2;
|
|
45
|
+
int32 enabledCount = 3 [deprecated = true];
|
|
46
|
+
int32 disabledCount = 4 [deprecated = true];
|
|
47
|
+
optional string feature = 5;
|
|
48
|
+
double value = 6 [deprecated = true];
|
|
49
|
+
optional double valueDisabled = 7 [deprecated = true];
|
|
50
|
+
|
|
51
|
+
map<string, double> variantValues = 8;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
message MetricResult {
|
|
55
|
+
int32 count = 1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
service Metrics {
|
|
59
|
+
rpc SendMetrics(MetricStat) returns (MetricResult);
|
|
60
|
+
}
|
data/proto/usage.proto
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package Usage;
|
|
4
|
+
|
|
5
|
+
option go_package = "github.com/ops-ai/Toggly.FeatureManagement/toggly-go/toggly/usage/usagepb";
|
|
6
|
+
|
|
7
|
+
import "google/protobuf/timestamp.proto";
|
|
8
|
+
|
|
9
|
+
message FeatureStat {
|
|
10
|
+
string appKey = 1;
|
|
11
|
+
string environment = 2;
|
|
12
|
+
google.protobuf.Timestamp time = 3;
|
|
13
|
+
repeated StatMessage stats = 4;
|
|
14
|
+
int32 totalUniqueUsers = 5;
|
|
15
|
+
optional string instanceName = 6;
|
|
16
|
+
optional google.protobuf.Timestamp processStartTime = 7;
|
|
17
|
+
optional string appVersion = 8;
|
|
18
|
+
repeated int32 uniqueUserHashes = 9; // Application-level unique user ID hashes
|
|
19
|
+
optional int32 definitionCacheHits = 10; // SDK-reported definition-refresh cache hits (batch delta)
|
|
20
|
+
optional int32 definitionCacheMisses = 11; // SDK-reported definition-refresh cache misses (batch delta)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
message StatMessage {
|
|
24
|
+
string feature = 1;
|
|
25
|
+
int32 enabledCount = 2 [deprecated = true]; // Legacy: use variantStats instead
|
|
26
|
+
int32 disabledCount = 3 [deprecated = true]; // Legacy: use variantStats instead
|
|
27
|
+
int32 uniqueContextIdentifierEnabledCount = 4;
|
|
28
|
+
int32 uniqueContextIdentifierDisabledCount = 5;
|
|
29
|
+
int32 uniqueRequestEnabledCount = 6 [deprecated = true]; // Legacy: use variantStats instead
|
|
30
|
+
int32 uniqueRequestDisabledCount = 7 [deprecated = true]; // Legacy: use variantStats instead
|
|
31
|
+
int32 usedCount = 8 [deprecated = true]; // Legacy: use variantStats instead
|
|
32
|
+
int32 uniqueUsersUsedCount = 9;
|
|
33
|
+
repeated int32 uniqueUserHashes = 10; // Unique user ID hashes for "used" tracking
|
|
34
|
+
|
|
35
|
+
// Multi-variate support - all new metrics should use this
|
|
36
|
+
map<string, VariantStats> variantStats = 11; // Key: variant name (e.g., "enabled", "disabled")
|
|
37
|
+
|
|
38
|
+
// Unique user tracking for "viewed" metric (per feature, not per variant)
|
|
39
|
+
repeated int32 uniqueViewedUserHashes = 12;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
message VariantStats {
|
|
43
|
+
int32 checkCount = 1;
|
|
44
|
+
int32 requestCount = 2;
|
|
45
|
+
int32 usedCount = 3;
|
|
46
|
+
int32 viewedCount = 4;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
message StatResult {
|
|
50
|
+
int32 featureCount = 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
service Usage {
|
|
54
|
+
rpc SendStats(FeatureStat) returns (StatResult);
|
|
55
|
+
}
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: toggly
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ops.ai
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: High-performance Ruby SDK for Toggly feature flag management. Works with
|
|
14
14
|
or without Toggly.io.
|
|
@@ -23,8 +23,11 @@ files:
|
|
|
23
23
|
- README.md
|
|
24
24
|
- lib/toggly.rb
|
|
25
25
|
- lib/toggly/client.rb
|
|
26
|
+
- lib/toggly/client/cache_telemetry.rb
|
|
27
|
+
- lib/toggly/client/snapshot_support.rb
|
|
26
28
|
- lib/toggly/config.rb
|
|
27
29
|
- lib/toggly/context.rb
|
|
30
|
+
- lib/toggly/definition_cache.rb
|
|
28
31
|
- lib/toggly/definitions_provider.rb
|
|
29
32
|
- lib/toggly/entity_context.rb
|
|
30
33
|
- lib/toggly/errors.rb
|
|
@@ -32,17 +35,40 @@ files:
|
|
|
32
35
|
- lib/toggly/evaluators/always_off.rb
|
|
33
36
|
- lib/toggly/evaluators/always_on.rb
|
|
34
37
|
- lib/toggly/evaluators/base.rb
|
|
38
|
+
- lib/toggly/evaluators/browser_family.rb
|
|
39
|
+
- lib/toggly/evaluators/browser_language.rb
|
|
35
40
|
- lib/toggly/evaluators/context_property.rb
|
|
36
41
|
- lib/toggly/evaluators/contextual_targeting.rb
|
|
42
|
+
- lib/toggly/evaluators/country.rb
|
|
43
|
+
- lib/toggly/evaluators/device_type.rb
|
|
44
|
+
- lib/toggly/evaluators/operating_system.rb
|
|
37
45
|
- lib/toggly/evaluators/percentage.rb
|
|
46
|
+
- lib/toggly/evaluators/segment_helpers.rb
|
|
38
47
|
- lib/toggly/evaluators/targeting.rb
|
|
39
48
|
- lib/toggly/evaluators/time_window.rb
|
|
49
|
+
- lib/toggly/evaluators/user_claims.rb
|
|
40
50
|
- lib/toggly/feature_definition.rb
|
|
51
|
+
- lib/toggly/http_request_mapper.rb
|
|
41
52
|
- lib/toggly/registry.rb
|
|
53
|
+
- lib/toggly/request_context.rb
|
|
42
54
|
- lib/toggly/snapshot_providers/base.rb
|
|
43
55
|
- lib/toggly/snapshot_providers/file.rb
|
|
44
56
|
- lib/toggly/snapshot_providers/memory.rb
|
|
57
|
+
- lib/toggly/sticky_hash.rb
|
|
58
|
+
- lib/toggly/telemetry.rb
|
|
59
|
+
- lib/toggly/telemetry/grpc_clients.rb
|
|
60
|
+
- lib/toggly/telemetry/metrics_batcher.rb
|
|
61
|
+
- lib/toggly/telemetry/pb/metrics_pb.rb
|
|
62
|
+
- lib/toggly/telemetry/pb/metrics_services_pb.rb
|
|
63
|
+
- lib/toggly/telemetry/pb/usage_pb.rb
|
|
64
|
+
- lib/toggly/telemetry/pb/usage_services_pb.rb
|
|
65
|
+
- lib/toggly/telemetry/runtime.rb
|
|
66
|
+
- lib/toggly/telemetry/runtime_flush.rb
|
|
67
|
+
- lib/toggly/telemetry/usage_batcher.rb
|
|
68
|
+
- lib/toggly/user_agent_parser.rb
|
|
45
69
|
- lib/toggly/version.rb
|
|
70
|
+
- proto/metrics.proto
|
|
71
|
+
- proto/usage.proto
|
|
46
72
|
homepage: https://toggly.io
|
|
47
73
|
licenses:
|
|
48
74
|
- MIT
|
|
@@ -52,7 +78,7 @@ metadata:
|
|
|
52
78
|
changelog_uri: https://github.com/ops-ai/toggly-ruby/blob/main/CHANGELOG.md
|
|
53
79
|
documentation_uri: https://docs.toggly.io/sdks/ruby
|
|
54
80
|
rubygems_mfa_required: 'true'
|
|
55
|
-
optional_dependencies: websocket-client-simple
|
|
81
|
+
optional_dependencies: websocket-client-simple, grpc, google-protobuf
|
|
56
82
|
post_install_message:
|
|
57
83
|
rdoc_options: []
|
|
58
84
|
require_paths:
|