md-logstasher 1.8.0 → 1.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0348868a167435982eb59967a93c089a748c0c186fd9e4047a64437e868b0023'
4
- data.tar.gz: b5f0441ca7b83ce1a3aaf1bb0fab537fdab07a6d0c420f34ac75dbcbf426fbe4
3
+ metadata.gz: 1fe9fbb482168a2c0e95473e02f2b219cbf116ee4f2006fe6ed15a6cde16bb44
4
+ data.tar.gz: 9735b52eae692c0b08205949cc65f894a3351e4e6e0275f25cc8a1663d1076eb
5
5
  SHA512:
6
- metadata.gz: d7b469e1c11272f3ebabdbf8b218068ca979342a9aa5d2a2e0ea5e7d20f723e369d2f4304fe72650e60af1b76dc8763fbb3764891453eb16622a5a7f6f563a4a
7
- data.tar.gz: 84b8ca35715352709060707a86889dd3170985d2ed1224a55a583d478e73175b2d57f9d2b81c6a049d5801bbd56e92bbf7086b2c33f9e44f747c8627a20a4b9d
6
+ metadata.gz: db9a456790e5bf911c52f135cc1c9ce8f1486f6e47ed1aad91de52ccb9347cf6c86a83f453f8abd774be7836cfb91641f4911be017cfc23dc5463de52788e694
7
+ data.tar.gz: 4b2e935c1457a249a40297de6330ea991c5095539070acb75fe2f32d5b592039ad4c80b23b9e2ec7870a5211671a1cf188e4f568cc7b22dd207d81f85e941ed5
@@ -8,6 +8,7 @@ module LogStasher
8
8
  config.logstasher.silence_creation_message = true
9
9
  config.logstasher.logger = nil
10
10
  config.logstasher.log_level = ::Logger::INFO
11
+ config.logstasher.dry_validation_contract = nil
11
12
 
12
13
  config.logstasher.metadata = {}
13
14
  config.before_initialize do
@@ -20,6 +21,7 @@ module LogStasher
20
21
  ::LogStasher.logger = options.logger || default_logger
21
22
  ::LogStasher.logger.level = options.log_level
22
23
  ::LogStasher.metadata = options.metadata
24
+ ::LogStasher.dry_validation_contract = options.dry_validation_contract
23
25
  end
24
26
 
25
27
  initializer 'logstasher.load' do
@@ -1,3 +1,3 @@
1
1
  module LogStasher
2
- VERSION = "1.8.0"
2
+ VERSION = "1.9.0"
3
3
  end
data/lib/logstasher.rb CHANGED
@@ -36,6 +36,17 @@ module LogStasher
36
36
  @append_fields_callback = block
37
37
  end
38
38
 
39
+ def dry_validation_contract=(contract)
40
+ if contract && !contract.is_a?(::Dry::Validation::Contract)
41
+ raise ArgumentError, "Expected a Dry::Validation::Contract, got #{contract.class}"
42
+ end
43
+ @dry_validation_contract = contract
44
+ end
45
+
46
+ def dry_validation_contract
47
+ @dry_validation_contract
48
+ end
49
+
39
50
  def enabled?
40
51
  if @enabled.nil?
41
52
  @enabled = false
@@ -81,6 +92,9 @@ module LogStasher
81
92
  # example.
82
93
  payload = ::LogStash::Event.new(payload) if as_logstash_event
83
94
 
95
+ # Validate payload if a dry_validation_contract is configured
96
+ validate_payload(payload) if dry_validation_contract
97
+
84
98
  logger << payload.to_json + $INPUT_RECORD_SEPARATOR
85
99
  end
86
100
 
@@ -99,6 +113,22 @@ module LogStasher
99
113
 
100
114
  @silence_standard_logging
101
115
  end
116
+
117
+ private
118
+
119
+ def validate_payload(payload)
120
+ return unless payload.is_a?(::LogStash::Event) || payload.is_a?(::Hash)
121
+
122
+ validation = dry_validation_contract.call(payload.to_hash)
123
+
124
+ validation_payload = {
125
+ dry_validation_success: validation.success?,
126
+ dry_validation_errors: validation.errors.to_h.to_json
127
+ }
128
+
129
+ return payload.append(validation_payload) if payload.is_a?(::LogStash::Event)
130
+ return payload.deep_merge!(validation_payload) if payload.is_a?(::Hash)
131
+ end
102
132
  end
103
133
  end
104
134
 
data/logstasher.gemspec CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.require_paths = ["lib"]
19
19
 
20
20
  s.add_runtime_dependency "logstash-event", "~> 1.2"
21
+ s.add_runtime_dependency "dry-validation", ">= 1.11.0"
21
22
 
22
23
  s.add_development_dependency "redis"
23
24
  s.add_development_dependency "rspec"
@@ -1,13 +1,19 @@
1
1
  require "spec_helper"
2
+ require "dry-validation"
2
3
 
3
4
  describe ::LogStasher do
5
+ before(:each) do
6
+ # Reset state before each test
7
+ ::LogStasher.metadata = {}
8
+ ::LogStasher.dry_validation_contract = nil
9
+ end
4
10
  describe "#log_as_json" do
5
11
  it "calls the logger with the payload" do
6
12
  expect(::LogStasher.logger).to receive(:<<) do |json|
7
13
  expect(::JSON.parse(json)).to eq("yolo" => "brolo")
8
14
  end
9
15
 
10
- ::LogStasher.log_as_json(:yolo => :brolo)
16
+ ::LogStasher.log_as_json({"yolo" => "brolo"})
11
17
  end
12
18
 
13
19
  context "with event" do
@@ -20,7 +26,7 @@ describe ::LogStasher do
20
26
  expect(payload["yolo"]).to eq("brolo")
21
27
  end
22
28
 
23
- ::LogStasher.log_as_json({:yolo => :brolo}, :as_logstash_event => true)
29
+ ::LogStasher.log_as_json({"yolo" => "brolo"}, :as_logstash_event => true)
24
30
  end
25
31
  end
26
32
 
@@ -33,7 +39,7 @@ describe ::LogStasher do
33
39
  expect(::JSON.parse(json)).to eq("yolo" => "brolo", "metadata" => { "namespace" => "cooldude" })
34
40
  end
35
41
 
36
- ::LogStasher.log_as_json(:yolo => :brolo)
42
+ ::LogStasher.log_as_json({"yolo" => "brolo"})
37
43
  end
38
44
 
39
45
  it "merges metadata for LogStash::Event types" do
@@ -41,7 +47,7 @@ describe ::LogStasher do
41
47
  expect(::JSON.parse(json)).to match(a_hash_including("yolo" => "brolo", "metadata" => { "namespace" => "cooldude" }))
42
48
  end
43
49
 
44
- ::LogStasher.log_as_json(::LogStash::Event.new(:yolo => :brolo))
50
+ ::LogStasher.log_as_json(::LogStash::Event.new("yolo" => "brolo"))
45
51
  end
46
52
 
47
53
  it "does not merge metadata on an array" do
@@ -49,8 +55,122 @@ describe ::LogStasher do
49
55
  expect(::JSON.parse(json)).to eq([{ "yolo" => "brolo" }])
50
56
  end
51
57
 
52
- ::LogStasher.log_as_json([{:yolo => :brolo}])
58
+ ::LogStasher.log_as_json([{"yolo" => "brolo"}])
59
+ end
60
+ end
61
+
62
+ context "with dry validation contract" do
63
+ let(:validation_contract) do
64
+ Class.new(Dry::Validation::Contract) do
65
+ params do
66
+ required(:yolo).filled(:string)
67
+ end
68
+ end.new
69
+ end
70
+
71
+ before do
72
+ ::LogStasher.metadata = { :namespace => :cooldude }
73
+ ::LogStasher.dry_validation_contract = validation_contract
74
+ end
75
+
76
+ after do
77
+ ::LogStasher.metadata = {}
78
+ ::LogStasher.dry_validation_contract = nil
79
+ end
80
+
81
+ it "validates LogStash::Event payload and appends validation metadata on success" do
82
+ expect(::LogStasher.logger).to receive(:<<) do |json|
83
+ payload = ::JSON.parse(json)
84
+ expect(payload["dry_validation_errors"]).to eq("{}")
85
+ expect(payload["dry_validation_success"]).to be true
86
+ expect(payload["yolo"]).to eq("brolo")
87
+ expect(payload["metadata"]["namespace"]).to eq("cooldude")
88
+ end
89
+
90
+ ::LogStasher.log_as_json(::LogStash::Event.new("yolo" => "brolo"))
91
+ end
92
+
93
+ it "validates LogStash::Event payload and appends validation metadata on failure" do
94
+ expect(::LogStasher.logger).to receive(:<<) do |json|
95
+ payload = ::JSON.parse(json)
96
+ expect(payload["dry_validation_errors"]).to eq("{\"yolo\":[\"must be a string\"]}")
97
+ expect(payload["dry_validation_success"]).to be false
98
+ expect(payload["yolo"]).to eq(123)
99
+ expect(payload["metadata"]["namespace"]).to eq("cooldude")
100
+ end
101
+
102
+ ::LogStasher.log_as_json(::LogStash::Event.new("yolo" => 123))
103
+ end
104
+
105
+ it "validates hash payload and merges validation metadata on success" do
106
+ expect(::LogStasher.logger).to receive(:<<) do |json|
107
+ payload = ::JSON.parse(json)
108
+ expect(payload["dry_validation_errors"]).to eq("{}")
109
+ expect(payload["dry_validation_success"]).to be true
110
+ expect(payload["yolo"]).to eq("brolo")
111
+ expect(payload["metadata"]["namespace"]).to eq("cooldude")
112
+ end
113
+
114
+ ::LogStasher.log_as_json({"yolo" => "brolo"})
115
+ end
116
+
117
+ it "validates hash payload and merges validation metadata on failure" do
118
+ expect(::LogStasher.logger).to receive(:<<) do |json|
119
+ payload = ::JSON.parse(json)
120
+ expect(payload["dry_validation_errors"]).to eq("{\"yolo\":[\"must be a string\"]}")
121
+ expect(payload["dry_validation_success"]).to be false
122
+ expect(payload["yolo"]).to eq(123)
123
+ expect(payload["metadata"]["namespace"]).to eq("cooldude")
124
+ end
125
+
126
+ ::LogStasher.log_as_json({"yolo" => 123})
53
127
  end
128
+
129
+ it "does not validate array payloads" do
130
+ expect(::LogStasher.logger).to receive(:<<) do |json|
131
+ payload = ::JSON.parse(json)
132
+ expect(payload).to eq([{ "yolo" => "brolo" }])
133
+ end
134
+
135
+ ::LogStasher.log_as_json([{"yolo" => "brolo"}])
136
+ end
137
+ end
138
+ end
139
+
140
+ describe "#dry_validation_contract=" do
141
+ it "accepts a valid Dry::Validation::Contract" do
142
+ contract = Class.new(Dry::Validation::Contract) do
143
+ params do
144
+ required(:test).filled(:string)
145
+ end
146
+ end.new
147
+
148
+ expect { ::LogStasher.dry_validation_contract = contract }.not_to raise_error
149
+ expect(::LogStasher.dry_validation_contract).to eq(contract)
150
+ end
151
+
152
+ it "accepts nil" do
153
+ expect { ::LogStasher.dry_validation_contract = nil }.not_to raise_error
154
+ expect(::LogStasher.dry_validation_contract).to be_nil
155
+ end
156
+
157
+ it "raises ArgumentError for non-Contract objects" do
158
+ expect { ::LogStasher.dry_validation_contract = "not a contract" }.to raise_error(
159
+ ArgumentError, "Expected a Dry::Validation::Contract, got String"
160
+ )
161
+ end
162
+ end
163
+
164
+ describe "#dry_validation_contract" do
165
+ it "returns the stored contract" do
166
+ contract = double("contract")
167
+ ::LogStasher.instance_variable_set(:@dry_validation_contract, contract)
168
+ expect(::LogStasher.dry_validation_contract).to eq(contract)
169
+ end
170
+
171
+ it "returns nil when no contract is set" do
172
+ ::LogStasher.instance_variable_set(:@dry_validation_contract, nil)
173
+ expect(::LogStasher.dry_validation_contract).to be_nil
54
174
  end
55
175
  end
56
176
 
@@ -44,11 +44,13 @@ describe ::LogStasher::Railtie do
44
44
  config.include_parameters = "include_parameters"
45
45
  config.serialize_parameters = "serialize_parameters"
46
46
  config.silence_standard_logging = "silence_standard_logging"
47
+ config.dry_validation_contract = "dry_validation_contract"
47
48
 
48
49
  expect(::LogStasher).to receive(:enabled=).with("enabled")
49
50
  expect(::LogStasher).to receive(:include_parameters=).with("include_parameters")
50
51
  expect(::LogStasher).to receive(:serialize_parameters=).with("serialize_parameters")
51
52
  expect(::LogStasher).to receive(:silence_standard_logging=).with("silence_standard_logging")
53
+ expect(::LogStasher).to receive(:dry_validation_contract=).with("dry_validation_contract")
52
54
  expect(::LogStasher).to receive(:logger=).with(config.logger).and_call_original
53
55
  expect(config.logger).to receive(:level=).with("log_level")
54
56
 
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: md-logstasher
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Devin Christensen
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-01-22 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: logstash-event
@@ -24,6 +23,20 @@ dependencies:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
25
  version: '1.2'
26
+ - !ruby/object:Gem::Dependency
27
+ name: dry-validation
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.11.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 1.11.0
27
40
  - !ruby/object:Gem::Dependency
28
41
  name: redis
29
42
  requirement: !ruby/object:Gem::Requirement
@@ -108,7 +121,6 @@ homepage: https://github.com/moneydesktop/logstasher
108
121
  licenses:
109
122
  - MIT
110
123
  metadata: {}
111
- post_install_message:
112
124
  rdoc_options: []
113
125
  require_paths:
114
126
  - lib
@@ -123,8 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
135
  - !ruby/object:Gem::Version
124
136
  version: '0'
125
137
  requirements: []
126
- rubygems_version: 3.4.21
127
- signing_key:
138
+ rubygems_version: 3.6.9
128
139
  specification_version: 4
129
140
  summary: Awesome rails logs
130
141
  test_files: