prefab-cloud-ruby 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|