prefab-cloud-ruby 1.0.1 → 1.1.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 +8 -0
- data/VERSION +1 -1
- data/lib/prefab/client.rb +2 -2
- data/lib/prefab/context_shape_aggregator.rb +1 -1
- data/lib/prefab/evaluation_summary_aggregator.rb +1 -1
- data/lib/prefab/example_contexts_aggregator.rb +1 -1
- data/lib/prefab/log_path_aggregator.rb +4 -1
- data/lib/prefab/logger_client.rb +25 -26
- data/lib/prefab/options.rb +16 -10
- data/lib/prefab/periodic_sync.rb +4 -0
- data/prefab-cloud-ruby.gemspec +3 -3
- data/test/integration_test.rb +54 -4
- data/test/integration_test_helpers.rb +113 -0
- data/test/support/common_helpers.rb +11 -7
- data/test/test_integration.rb +14 -11
- data/test/test_logger.rb +40 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e3a735317d9c319aace8ce4cbc99c28a99ed83d23bda5a401c781a6e4e370c51
|
4
|
+
data.tar.gz: c9299c6f257d48b07f90a427d2e6b80b2db8c1daf5e3be5c92df34b3c13d76c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 722133d87e4a67ccce34e18d417b40e904da68e686b128badbde3d2a98a5b2b9e0a90f68c001de63cfc9877edf43982f4ffd59bc4dde0dcc6c10e43dc6a3cd83
|
7
|
+
data.tar.gz: 4673e84c936cf72f502402956b846ec14c8cbaaf90d2a90c794e0db4a352f8000cbb1477bd2d43abe685937879cdf6263dc63cfcf0218e7b15265876990c6a84
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## Unreleased
|
4
|
+
|
5
|
+
## 1.1.0 - 2023-09-18
|
6
|
+
|
7
|
+
- Add support for structured logging (#143)
|
8
|
+
- Ability to pass a hash of key/value context pairs to any of the user-facing log methods
|
9
|
+
|
10
|
+
|
3
11
|
## 1.0.1 - 2023-08-17
|
4
12
|
|
5
13
|
- Bug fix for StringList w/ ExampleContextsAggregator (#141)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0
|
1
|
+
1.1.0
|
data/lib/prefab/client.rb
CHANGED
@@ -99,8 +99,8 @@ module Prefab
|
|
99
99
|
resolver.on_update(&block)
|
100
100
|
end
|
101
101
|
|
102
|
-
def log_internal(level, msg, path = nil)
|
103
|
-
log.log_internal msg, path, nil, level
|
102
|
+
def log_internal(level, msg, path = nil, **tags)
|
103
|
+
log.log_internal msg, path, nil, level, tags
|
104
104
|
end
|
105
105
|
|
106
106
|
def enabled?(feature_name, jit_context = NO_DEFAULT_PROVIDED)
|
@@ -55,7 +55,7 @@ module Prefab
|
|
55
55
|
summaries: summaries(to_ship)
|
56
56
|
)
|
57
57
|
|
58
|
-
result =
|
58
|
+
result = post('/api/v1/telemetry', events(summaries_proto))
|
59
59
|
|
60
60
|
log_internal "Uploaded #{to_ship.size} summaries: #{result.status}"
|
61
61
|
end
|
@@ -45,7 +45,7 @@ module Prefab
|
|
45
45
|
pool.post do
|
46
46
|
log_internal "Flushing #{to_ship.size} examples"
|
47
47
|
|
48
|
-
result =
|
48
|
+
result = post('/api/v1/telemetry', events(to_ship))
|
49
49
|
|
50
50
|
log_internal "Uploaded #{to_ship.size} examples: #{result.status}"
|
51
51
|
end
|
@@ -25,6 +25,9 @@ module Prefab
|
|
25
25
|
|
26
26
|
@data = Concurrent::Map.new
|
27
27
|
|
28
|
+
@last_data_sent = nil
|
29
|
+
@last_request = nil
|
30
|
+
|
28
31
|
start_periodic_sync(sync_interval)
|
29
32
|
end
|
30
33
|
|
@@ -55,7 +58,7 @@ module Prefab
|
|
55
58
|
namespace: @client.namespace
|
56
59
|
)
|
57
60
|
|
58
|
-
result =
|
61
|
+
result = post('/api/v1/known-loggers', loggers)
|
59
62
|
|
60
63
|
log_internal "Uploaded #{to_ship.size} paths: #{result.status}"
|
61
64
|
end
|
data/lib/prefab/logger_client.rb
CHANGED
@@ -27,26 +27,26 @@ module Prefab
|
|
27
27
|
@log_path_aggregator = log_path_aggregator
|
28
28
|
end
|
29
29
|
|
30
|
-
def add_internal(severity, message, progname, loc, &block)
|
30
|
+
def add_internal(severity, message, progname, loc, log_context={}, &block)
|
31
31
|
path_loc = get_loc_path(loc)
|
32
32
|
path = @prefix + path_loc
|
33
33
|
|
34
34
|
@log_path_aggregator&.push(path_loc, severity)
|
35
35
|
|
36
|
-
log(message, path, progname, severity, &block)
|
36
|
+
log(message, path, progname, severity, log_context, &block)
|
37
37
|
end
|
38
38
|
|
39
|
-
def log_internal(message, path, progname, severity, &block)
|
39
|
+
def log_internal(message, path, progname, severity, log_context={}, &block)
|
40
40
|
path = if path
|
41
41
|
"#{INTERNAL_PREFIX}.#{path}"
|
42
42
|
else
|
43
43
|
INTERNAL_PREFIX
|
44
44
|
end
|
45
45
|
|
46
|
-
log(message, path, progname, severity, &block)
|
46
|
+
log(message, path, progname, severity, log_context, &block)
|
47
47
|
end
|
48
48
|
|
49
|
-
def log(message, path, progname, severity)
|
49
|
+
def log(message, path, progname, severity, log_context={})
|
50
50
|
severity ||= ::Logger::UNKNOWN
|
51
51
|
|
52
52
|
return true if @logdev.nil? || severity < level_of(path) || @silences[local_log_id]
|
@@ -63,29 +63,29 @@ module Prefab
|
|
63
63
|
end
|
64
64
|
|
65
65
|
@logdev.write(
|
66
|
-
format_message(format_severity(severity), Time.now, progname, message, path)
|
66
|
+
format_message(format_severity(severity), Time.now, progname, message, path, log_context)
|
67
67
|
)
|
68
68
|
true
|
69
69
|
end
|
70
70
|
|
71
|
-
def debug(progname = nil, &block)
|
72
|
-
add_internal(DEBUG, nil, progname, caller_locations(1, 1)[0], &block)
|
71
|
+
def debug(progname = nil, **log_context, &block)
|
72
|
+
add_internal(DEBUG, nil, progname, caller_locations(1, 1)[0], log_context, &block)
|
73
73
|
end
|
74
74
|
|
75
|
-
def info(progname = nil, &block)
|
76
|
-
add_internal(INFO, nil, progname, caller_locations(1, 1)[0], &block)
|
75
|
+
def info(progname = nil, **log_context, &block)
|
76
|
+
add_internal(INFO, nil, progname, caller_locations(1, 1)[0], log_context, &block)
|
77
77
|
end
|
78
78
|
|
79
|
-
def warn(progname = nil, &block)
|
80
|
-
add_internal(WARN, nil, progname, caller_locations(1, 1)[0], &block)
|
79
|
+
def warn(progname = nil, **log_context, &block)
|
80
|
+
add_internal(WARN, nil, progname, caller_locations(1, 1)[0], log_context, &block)
|
81
81
|
end
|
82
82
|
|
83
|
-
def error(progname = nil, &block)
|
84
|
-
add_internal(ERROR, nil, progname, caller_locations(1, 1)[0], &block)
|
83
|
+
def error(progname = nil, **log_context, &block)
|
84
|
+
add_internal(ERROR, nil, progname, caller_locations(1, 1)[0], log_context, &block)
|
85
85
|
end
|
86
86
|
|
87
|
-
def fatal(progname = nil, &block)
|
88
|
-
add_internal(FATAL, nil, progname, caller_locations(1, 1)[0], &block)
|
87
|
+
def fatal(progname = nil, **log_context, &block)
|
88
|
+
add_internal(FATAL, nil, progname, caller_locations(1, 1)[0], log_context, &block)
|
89
89
|
end
|
90
90
|
|
91
91
|
def debug?
|
@@ -168,18 +168,17 @@ module Prefab
|
|
168
168
|
path
|
169
169
|
end
|
170
170
|
|
171
|
-
def format_message(severity, datetime, progname, msg, path = nil)
|
171
|
+
def format_message(severity, datetime, progname, msg, path = nil, log_context={})
|
172
172
|
formatter = (@formatter || @default_formatter)
|
173
173
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
(progname.nil? || progname.empty?) ? path : "#{progname}: #{path}"
|
174
|
+
formatter.call(
|
175
|
+
severity: severity,
|
176
|
+
datetime: datetime,
|
177
|
+
progname: progname,
|
178
|
+
path: path,
|
179
|
+
message: msg,
|
180
|
+
log_context: log_context
|
181
|
+
)
|
183
182
|
end
|
184
183
|
end
|
185
184
|
|
data/lib/prefab/options.rb
CHANGED
@@ -17,17 +17,23 @@ module Prefab
|
|
17
17
|
attr_reader :prefab_envs
|
18
18
|
attr_reader :collect_sync_interval
|
19
19
|
|
20
|
-
DEFAULT_LOG_FORMATTER = proc { |
|
21
|
-
|
20
|
+
DEFAULT_LOG_FORMATTER = proc { |data|
|
21
|
+
severity = data[:severity]
|
22
|
+
datetime = data[:datetime]
|
23
|
+
progname = data[:progname]
|
24
|
+
path = data[:path]
|
25
|
+
msg = data[:message]
|
26
|
+
log_context = data[:log_context]
|
27
|
+
|
28
|
+
progname = (progname.nil? || progname.empty?) ? path : "#{progname}: #{path}"
|
29
|
+
|
30
|
+
formatted_log_context = log_context.sort.map{|k, v| "#{k}=#{v}" }.join(" ")
|
31
|
+
"#{severity.ljust(5)} #{datetime}:#{' ' if progname}#{progname} #{msg}#{log_context.any? ? " " + formatted_log_context : ""}\n"
|
22
32
|
}
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
progname: progname,
|
28
|
-
message: msg,
|
29
|
-
path: path
|
30
|
-
}.compact.to_json << "\n"
|
33
|
+
|
34
|
+
JSON_LOG_FORMATTER = proc { |data|
|
35
|
+
log_context = data.delete(:log_context)
|
36
|
+
data.merge(log_context).compact.to_json << "\n"
|
31
37
|
}
|
32
38
|
|
33
39
|
module ON_INITIALIZATION_FAILURE
|
data/lib/prefab/periodic_sync.rb
CHANGED
data/prefab-cloud-ruby.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: prefab-cloud-ruby 1.0
|
5
|
+
# stub: prefab-cloud-ruby 1.1.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "prefab-cloud-ruby".freeze
|
9
|
-
s.version = "1.0
|
9
|
+
s.version = "1.1.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["Jeff Dwyer".freeze]
|
14
|
-
s.date = "2023-
|
14
|
+
s.date = "2023-09-18"
|
15
15
|
s.description = "Feature Flags, Live Config, and Dynamic Log Levels as a service".freeze
|
16
16
|
s.email = "jdwyer@prefab.cloud".freeze
|
17
17
|
s.executables = ["console".freeze]
|
data/test/integration_test.rb
CHANGED
@@ -1,18 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class IntegrationTest
|
4
|
-
attr_reader :func, :input, :expected, :test_client
|
4
|
+
attr_reader :func, :input, :expected, :data, :expected_data, :aggregator, :endpoint, :test_client
|
5
5
|
|
6
6
|
def initialize(test_data)
|
7
7
|
@client_overrides = parse_client_overrides(test_data['client_overrides'])
|
8
8
|
@func = parse_function(test_data['function'])
|
9
9
|
@input = parse_input(test_data['input'])
|
10
10
|
@expected = parse_expected(test_data['expected'])
|
11
|
-
@
|
11
|
+
@data = test_data['data']
|
12
|
+
@expected_data = test_data['expected_data']
|
13
|
+
@aggregator = test_data['aggregator']
|
14
|
+
@endpoint = test_data['endpoint']
|
15
|
+
@test_client = capture_telemetry(base_client)
|
12
16
|
end
|
13
17
|
|
14
18
|
def test_type
|
15
|
-
if @
|
19
|
+
if @data
|
20
|
+
:telemetry
|
21
|
+
elsif @input[0] && @input[0].start_with?('log-level.')
|
16
22
|
:log_level
|
17
23
|
elsif @expected[:status] == 'raise'
|
18
24
|
:raise
|
@@ -23,6 +29,18 @@ class IntegrationTest
|
|
23
29
|
end
|
24
30
|
end
|
25
31
|
|
32
|
+
def last_data_sent
|
33
|
+
test_client.last_data_sent
|
34
|
+
end
|
35
|
+
|
36
|
+
def last_post_result
|
37
|
+
test_client.last_post_result
|
38
|
+
end
|
39
|
+
|
40
|
+
def last_post_endpoint
|
41
|
+
test_client.last_post_endpoint
|
42
|
+
end
|
43
|
+
|
26
44
|
private
|
27
45
|
|
28
46
|
def parse_client_overrides(overrides)
|
@@ -42,6 +60,8 @@ class IntegrationTest
|
|
42
60
|
end
|
43
61
|
|
44
62
|
def parse_input(input)
|
63
|
+
return nil if input.nil?
|
64
|
+
|
45
65
|
if input['key']
|
46
66
|
parse_config_input(input)
|
47
67
|
elsif input['flag']
|
@@ -62,6 +82,8 @@ class IntegrationTest
|
|
62
82
|
end
|
63
83
|
|
64
84
|
def parse_expected(expected)
|
85
|
+
return {} if expected.nil?
|
86
|
+
|
65
87
|
{
|
66
88
|
status: expected['status'],
|
67
89
|
error: parse_error_type(expected['error']),
|
@@ -73,6 +95,7 @@ class IntegrationTest
|
|
73
95
|
def parse_error_type(error_type)
|
74
96
|
case error_type
|
75
97
|
when 'missing_default' then Prefab::Errors::MissingDefaultError
|
98
|
+
when 'initialization_timeout' then Prefab::Errors::InitializationTimeoutError
|
76
99
|
end
|
77
100
|
end
|
78
101
|
|
@@ -87,7 +110,34 @@ class IntegrationTest
|
|
87
110
|
prefab_envs: ['unit_tests'],
|
88
111
|
prefab_datasources: Prefab::Options::DATASOURCES::ALL,
|
89
112
|
api_key: ENV['PREFAB_INTEGRATION_TEST_API_KEY'],
|
90
|
-
prefab_api_url: 'https://api.staging-prefab.cloud'
|
113
|
+
prefab_api_url: 'https://api.staging-prefab.cloud',
|
91
114
|
}.merge(@client_overrides))
|
92
115
|
end
|
116
|
+
|
117
|
+
def capture_telemetry(client)
|
118
|
+
client.define_singleton_method(:post) do |url, data|
|
119
|
+
client.instance_variable_set(:@last_data_sent, data)
|
120
|
+
client.instance_variable_set(:@last_post_endpoint, url)
|
121
|
+
|
122
|
+
result = super(url, data)
|
123
|
+
|
124
|
+
client.instance_variable_set(:@last_post_result, result)
|
125
|
+
|
126
|
+
result
|
127
|
+
end
|
128
|
+
|
129
|
+
client.define_singleton_method(:last_data_sent) do
|
130
|
+
client.instance_variable_get(:@last_data_sent)
|
131
|
+
end
|
132
|
+
|
133
|
+
client.define_singleton_method(:last_post_endpoint) do
|
134
|
+
client.instance_variable_get(:@last_post_endpoint)
|
135
|
+
end
|
136
|
+
|
137
|
+
client.define_singleton_method(:last_post_result) do
|
138
|
+
client.instance_variable_get(:@last_post_result)
|
139
|
+
end
|
140
|
+
|
141
|
+
client
|
142
|
+
end
|
93
143
|
end
|
@@ -33,4 +33,117 @@ module IntegrationTestHelpers
|
|
33
33
|
.select { |file| file =~ /\.ya?ml$/ }
|
34
34
|
end
|
35
35
|
end
|
36
|
+
|
37
|
+
def self.prepare_post_data(it)
|
38
|
+
case it.aggregator
|
39
|
+
when "log_path"
|
40
|
+
aggregator = it.test_client.log_path_aggregator
|
41
|
+
|
42
|
+
it.data.each do |(path, data)|
|
43
|
+
data.each_with_index do |count, severity|
|
44
|
+
count.times { aggregator.push(path, severity) }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
expected_loggers = Hash.new { |h, k| h[k] = PrefabProto::Logger.new }
|
49
|
+
|
50
|
+
it.expected_data.each do |data|
|
51
|
+
data["counts"].each do |(severity, count)|
|
52
|
+
expected_loggers[data["logger_name"]][severity] = count
|
53
|
+
expected_loggers[data["logger_name"]]["logger_name"] = data["logger_name"]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
[aggregator, ->(data) { data.loggers }, expected_loggers.values]
|
58
|
+
when "context_shape"
|
59
|
+
aggregator = it.test_client.context_shape_aggregator
|
60
|
+
|
61
|
+
context = Prefab::Context.new(it.data)
|
62
|
+
|
63
|
+
aggregator.push(context)
|
64
|
+
|
65
|
+
expected = it.expected_data.map do |data|
|
66
|
+
PrefabProto::ContextShape.new(
|
67
|
+
name: data["name"],
|
68
|
+
field_types: data["field_types"]
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
[aggregator, ->(data) { data.shapes }, expected]
|
73
|
+
when "evaluation_summary"
|
74
|
+
aggregator = it.test_client.evaluation_summary_aggregator
|
75
|
+
|
76
|
+
aggregator.instance_variable_set("@data", Concurrent::Hash.new)
|
77
|
+
|
78
|
+
it.data.each do |key|
|
79
|
+
it.test_client.get(key)
|
80
|
+
end
|
81
|
+
|
82
|
+
expected_data = []
|
83
|
+
it.expected_data.each do |data|
|
84
|
+
value = if data["value_type"] == "string_list"
|
85
|
+
PrefabProto::StringList.new(values: data["value"])
|
86
|
+
else
|
87
|
+
data["value"]
|
88
|
+
end
|
89
|
+
expected_data << PrefabProto::ConfigEvaluationSummary.new(
|
90
|
+
key: data["key"],
|
91
|
+
type: data["type"].to_sym,
|
92
|
+
counters: [
|
93
|
+
PrefabProto::ConfigEvaluationCounter.new(
|
94
|
+
count: data["count"],
|
95
|
+
config_id: 0,
|
96
|
+
selected_value: PrefabProto::ConfigValue.new(data["value_type"] => value),
|
97
|
+
config_row_index: data["summary"]["config_row_index"],
|
98
|
+
conditional_value_index: data["summary"]["conditional_value_index"] || 0,
|
99
|
+
weighted_value_index: data["summary"]["weighted_value_index"],
|
100
|
+
reason: :UNKNOWN
|
101
|
+
)
|
102
|
+
]
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
[aggregator, ->(data) {
|
107
|
+
data.events[0].summaries.summaries.each { |e|
|
108
|
+
e.counters.each { |c|
|
109
|
+
c.config_id = 0
|
110
|
+
}
|
111
|
+
}
|
112
|
+
}, expected_data]
|
113
|
+
when "example_contexts"
|
114
|
+
aggregator = it.test_client.example_contexts_aggregator
|
115
|
+
|
116
|
+
it.data.each do |hash|
|
117
|
+
aggregator.record(Prefab::Context.new(hash))
|
118
|
+
end
|
119
|
+
|
120
|
+
expected_data = []
|
121
|
+
it.expected_data.each do |data|
|
122
|
+
expected_data << PrefabProto::ExampleContext.new(
|
123
|
+
timestamp: 0,
|
124
|
+
contextSet: PrefabProto::ContextSet.new(
|
125
|
+
contexts: data.map do |(k, vs)|
|
126
|
+
PrefabProto::Context.new(
|
127
|
+
type: k,
|
128
|
+
values: vs.map do |v|
|
129
|
+
[v["key"], PrefabProto::ConfigValue.new(v["value_type"] => v["value"])]
|
130
|
+
end.to_h
|
131
|
+
)
|
132
|
+
end
|
133
|
+
)
|
134
|
+
)
|
135
|
+
end
|
136
|
+
[aggregator, ->(data) { data.events[0].example_contexts.examples.each { |e| e.timestamp = 0 } }, expected_data]
|
137
|
+
else
|
138
|
+
puts "unknown aggregator #{it.aggregator}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.with_parent_context_maybe(context, &block)
|
143
|
+
if context
|
144
|
+
Prefab::Context.with_context(context, &block)
|
145
|
+
else
|
146
|
+
yield
|
147
|
+
end
|
148
|
+
end
|
36
149
|
end
|
@@ -82,6 +82,16 @@ module CommonHelpers
|
|
82
82
|
|
83
83
|
FakeResponse = Struct.new(:status, :body)
|
84
84
|
|
85
|
+
def wait_for(condition, max_wait: 2, sleep_time: 0.01)
|
86
|
+
wait_time = 0
|
87
|
+
while !condition.call
|
88
|
+
wait_time += sleep_time
|
89
|
+
sleep sleep_time
|
90
|
+
|
91
|
+
raise "Waited #{max_wait} seconds for the condition to be true, but it never was" if wait_time > max_wait
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
85
95
|
def wait_for_post_requests(client, max_wait: 2, sleep_time: 0.01)
|
86
96
|
# we use ivars to avoid re-mocking the post method on subsequent calls
|
87
97
|
client.instance_variable_set("@_requests", [])
|
@@ -99,13 +109,7 @@ module CommonHelpers
|
|
99
109
|
yield
|
100
110
|
|
101
111
|
# let the flush thread run
|
102
|
-
|
103
|
-
while client.instance_variable_get("@_requests").empty?
|
104
|
-
wait_time += sleep_time
|
105
|
-
sleep sleep_time
|
106
|
-
|
107
|
-
raise "Waited #{max_wait} seconds for the flush thread to run, but it never did" if wait_time > max_wait
|
108
|
-
end
|
112
|
+
wait_for -> { client.instance_variable_get("@_requests").size > 0 }, max_wait: max_wait, sleep_time: sleep_time
|
109
113
|
|
110
114
|
client.instance_variable_get("@_requests")
|
111
115
|
end
|
data/test/test_integration.rb
CHANGED
@@ -16,7 +16,7 @@ class TestIntegration < Minitest::Test
|
|
16
16
|
define_method(:"test_#{test['name']}_#{test_case['name']}") do
|
17
17
|
it = IntegrationTest.new(test_case)
|
18
18
|
|
19
|
-
with_parent_context_maybe(parent_context) do
|
19
|
+
IntegrationTestHelpers.with_parent_context_maybe(parent_context) do
|
20
20
|
case it.test_type
|
21
21
|
when :raise
|
22
22
|
err = assert_raises(it.expected[:error]) do
|
@@ -34,6 +34,19 @@ class TestIntegration < Minitest::Test
|
|
34
34
|
end
|
35
35
|
when :log_level
|
36
36
|
assert_equal it.expected[:value].to_sym, it.test_client.send(it.func, *it.input)
|
37
|
+
when :telemetry
|
38
|
+
aggregator, get_actual_data, expected = IntegrationTestHelpers.prepare_post_data(it)
|
39
|
+
aggregator.sync
|
40
|
+
|
41
|
+
wait_for -> { it.last_post_result&.status == 200 }
|
42
|
+
|
43
|
+
assert it.endpoint == it.last_post_endpoint
|
44
|
+
|
45
|
+
actual = get_actual_data[it.last_data_sent]
|
46
|
+
|
47
|
+
expected.all? do |expected|
|
48
|
+
assert actual.include?(expected)
|
49
|
+
end
|
37
50
|
else
|
38
51
|
raise "Unknown test type: #{it.test_type}"
|
39
52
|
end
|
@@ -42,14 +55,4 @@ class TestIntegration < Minitest::Test
|
|
42
55
|
end
|
43
56
|
end
|
44
57
|
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
def with_parent_context_maybe(context, &block)
|
49
|
-
if context
|
50
|
-
Prefab::Context.with_context(context, &block)
|
51
|
-
else
|
52
|
-
yield
|
53
|
-
end
|
54
|
-
end
|
55
58
|
end
|
data/test/test_logger.rb
CHANGED
@@ -404,6 +404,46 @@ class TestLogger < Minitest::Test
|
|
404
404
|
assert_logged io, 'ERROR', 'test.test_logger.test_logging_with_a_block', message
|
405
405
|
end
|
406
406
|
|
407
|
+
def test_structured_logging
|
408
|
+
prefab, io = captured_logger
|
409
|
+
message = 'HELLO'
|
410
|
+
|
411
|
+
prefab.log.error message, user: "michael", id: 123
|
412
|
+
|
413
|
+
assert_logged io, 'ERROR', 'test.test_logger.test_structured_logging', "#{message} id=123 user=michael"
|
414
|
+
end
|
415
|
+
|
416
|
+
def test_structured_json_logging
|
417
|
+
prefab, io = captured_logger(log_formatter: Prefab::Options::JSON_LOG_FORMATTER)
|
418
|
+
message = 'HELLO'
|
419
|
+
|
420
|
+
prefab.log.error message, user: "michael", id: 123
|
421
|
+
|
422
|
+
log_data = JSON.parse(io.string)
|
423
|
+
assert log_data["message"] == message
|
424
|
+
assert log_data["user"] == "michael"
|
425
|
+
assert log_data["id"] == 123
|
426
|
+
end
|
427
|
+
|
428
|
+
def test_structured_internal_logging
|
429
|
+
prefab, io = captured_logger
|
430
|
+
|
431
|
+
prefab.log.log_internal('test', 'test.path', '', ::Logger::WARN, user: "michael")
|
432
|
+
|
433
|
+
assert_logged io, 'WARN', 'cloud.prefab.client.test.path', "test user=michael"
|
434
|
+
end
|
435
|
+
|
436
|
+
def test_structured_block_logger
|
437
|
+
prefab, io = captured_logger
|
438
|
+
message = 'MY MESSAGE'
|
439
|
+
|
440
|
+
prefab.log.error user: "michael" do
|
441
|
+
message
|
442
|
+
end
|
443
|
+
|
444
|
+
assert_logged io, 'ERROR', 'test.test_logger.test_structured_block_logger', "#{message} user=michael"
|
445
|
+
end
|
446
|
+
|
407
447
|
private
|
408
448
|
|
409
449
|
def assert_logged(logged_io, level, path, message)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prefab-cloud-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Dwyer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-09-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|