logstash-output-lmlogs 1.2.0 → 1.3.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 +12 -0
- data/lib/logstash/outputs/lmlogs.rb +41 -34
- data/logstash-output-lmlogs.gemspec +1 -1
- data/spec/outputs/auth_spec.rb +60 -0
- data/spec/outputs/lmlogs_spec.rb +15 -14
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 870bd26e9fabeb697cb8dd8f66eeb7f243b4be3fcf51c0d3babb81260a08b3d9
|
4
|
+
data.tar.gz: 548fff67d397ef9a6c51a2bebb0c4f44d2b3decd57faa801bd9ac2e1048edad2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 504cdc43d302a8d504a38627e3b914e8514331ae889dbcfba7fa3f0da6f010aeb09aa19437f5d32e73e100db4d0f839f9c182eb4135b78cfb1d538a6ea0f4314
|
7
|
+
data.tar.gz: 78a8b8b391c4887bfa5a06b12d044d03c9d3b9f2cfdc9231ae5a9d0a70ac28d824e59ce493cf8a4f3d2fc7675ecd0a7ce8b7d71c60fa8fc57664a7937793ad07
|
data/CHANGELOG.md
CHANGED
@@ -1,2 +1,14 @@
|
|
1
1
|
## 1.0.0
|
2
2
|
- First version of the plugin
|
3
|
+
## 1.0.1
|
4
|
+
- Proxy support
|
5
|
+
## 1.0.2
|
6
|
+
- Update debug logs
|
7
|
+
## 1.1.0
|
8
|
+
- Disable mfa for gem push
|
9
|
+
## 1.2.0
|
10
|
+
- Add metadata by default to every log
|
11
|
+
## 1.2.1
|
12
|
+
- Fix ensuring metadata exists before deleting the original while forwarding to lm-logs
|
13
|
+
## 1.3.0
|
14
|
+
- Add bearer token support for authentication with Logicmonitor
|
@@ -30,7 +30,7 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
|
|
30
30
|
|
31
31
|
# Keep logstash timestamp
|
32
32
|
config :keep_timestamp, :validate => :boolean, :default => true
|
33
|
-
|
33
|
+
|
34
34
|
# Use a configured message key for timestamp values
|
35
35
|
# Valid timestamp formats are ISO8601 strings or epoch in seconds, milliseconds or nanoseconds
|
36
36
|
config :timestamp_is_key, :validate => :boolean, :default => false
|
@@ -91,13 +91,16 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
|
|
91
91
|
config :portal_name, :validate => :string, :required => true
|
92
92
|
|
93
93
|
# Username to use for HTTP auth.
|
94
|
-
config :access_id, :validate => :string, :required =>
|
94
|
+
config :access_id, :validate => :string, :required => false, :default => nil
|
95
95
|
|
96
96
|
# Include/Exclude metadata from sending to LM Logs
|
97
97
|
config :include_metadata, :validate => :boolean, :default => true
|
98
98
|
|
99
99
|
# Password to use for HTTP auth
|
100
|
-
config :access_key, :validate => :password, :required =>
|
100
|
+
config :access_key, :validate => :password, :required => false, :default => nil
|
101
|
+
|
102
|
+
# Use bearer token instead of access key/id for authentication.
|
103
|
+
config :bearer_token, :validate => :password, :required => false, :default => nil
|
101
104
|
|
102
105
|
@@MAX_PAYLOAD_SIZE = 8*1024*1024
|
103
106
|
|
@@ -110,9 +113,9 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
|
|
110
113
|
@total_failed = 0
|
111
114
|
logger.info("Initialized LogicMonitor output plugin with configuration",
|
112
115
|
:host => @host)
|
113
|
-
logger.info("Max Payload Size: ",
|
116
|
+
logger.info("Max Payload Size: ",
|
114
117
|
:size => @@MAX_PAYLOAD_SIZE)
|
115
|
-
|
118
|
+
configure_auth
|
116
119
|
end # def register
|
117
120
|
|
118
121
|
def client_config
|
@@ -137,19 +140,7 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
|
|
137
140
|
@proxy
|
138
141
|
end
|
139
142
|
|
140
|
-
|
141
|
-
if !@access_key || !@access_key.value
|
142
|
-
raise ::LogStash::ConfigurationError, "access_id '#{@access_id}' specified without access_key!"
|
143
|
-
end
|
144
|
-
|
145
|
-
# Symbolize keys if necessary
|
146
|
-
# c[:auth] = {
|
147
|
-
# :user => @access_id,
|
148
|
-
# :password => @access_key.value,
|
149
|
-
# :eager => true
|
150
|
-
# }
|
151
|
-
end
|
152
|
-
log_debug("manticore client config: ", :client => c)
|
143
|
+
log_debug("manticore client config: ", :client => c)
|
153
144
|
return c
|
154
145
|
end
|
155
146
|
|
@@ -168,21 +159,35 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
|
|
168
159
|
@client.close
|
169
160
|
end
|
170
161
|
|
171
|
-
|
162
|
+
def configure_auth
|
163
|
+
@use_bearer_instead_of_lmv1 = false
|
164
|
+
if @access_id == nil || @access_key.value == nil
|
165
|
+
@logger.info "Access Id or access key null. Using bearer token for authentication."
|
166
|
+
@use_bearer_instead_of_lmv1 = true
|
167
|
+
end
|
168
|
+
if @use_bearer_instead_of_lmv1 && @bearer_token.value == nil
|
169
|
+
@logger.error "Bearer token not specified. Either access_id and access_key both or bearer_token must be specified for authentication with Logicmonitor."
|
170
|
+
raise LogStash::ConfigurationError, 'No valid authentication specified. Either access_id and access_key both or bearer_token must be specified for authentication with Logicmonitor.'
|
171
|
+
end
|
172
|
+
end
|
172
173
|
def generate_auth_string(body)
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
174
|
+
if @use_bearer_instead_of_lmv1
|
175
|
+
return "Bearer #{@bearer_token.value}"
|
176
|
+
else
|
177
|
+
timestamp = DateTime.now.strftime('%Q')
|
178
|
+
hash_this = "POST#{timestamp}#{body}/log/ingest"
|
179
|
+
sign_this = OpenSSL::HMAC.hexdigest(
|
180
|
+
OpenSSL::Digest.new('sha256'),
|
181
|
+
"#{@access_key.value}",
|
182
|
+
hash_this
|
183
|
+
)
|
184
|
+
signature = Base64.strict_encode64(sign_this)
|
185
|
+
return "LMv1 #{@access_id}:#{signature}:#{timestamp}"
|
186
|
+
end
|
182
187
|
end
|
183
188
|
|
184
189
|
def send_batch(events)
|
185
|
-
log_debug("Started sending logs to LM: ",
|
190
|
+
log_debug("Started sending logs to LM: ",
|
186
191
|
:time => Time::now.utc)
|
187
192
|
url = "https://" + @portal_name + ".logicmonitor.com/rest/log/ingest"
|
188
193
|
body = events.to_json
|
@@ -249,7 +254,7 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
|
|
249
254
|
elsif debug
|
250
255
|
@logger.debug(message, *opts)
|
251
256
|
end
|
252
|
-
end
|
257
|
+
end
|
253
258
|
|
254
259
|
public
|
255
260
|
def multi_receive(events)
|
@@ -266,7 +271,9 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
|
|
266
271
|
if @include_metadata
|
267
272
|
lmlogs_event = event_json
|
268
273
|
lmlogs_event.delete("@timestamp") # remove redundant timestamp field
|
269
|
-
lmlogs_event
|
274
|
+
if lmlogs_event.dig("event", "original") != nil
|
275
|
+
lmlogs_event["event"].delete("original") # remove redundant log field
|
276
|
+
end
|
270
277
|
end
|
271
278
|
|
272
279
|
lmlogs_event["message"] = event.get(@message_key).to_s
|
@@ -276,7 +283,7 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
|
|
276
283
|
if @keep_timestamp
|
277
284
|
lmlogs_event["timestamp"] = event.get("@timestamp")
|
278
285
|
end
|
279
|
-
|
286
|
+
|
280
287
|
if @timestamp_is_key
|
281
288
|
lmlogs_event["timestamp"] = event.get(@timestamp_key.to_s)
|
282
289
|
end
|
@@ -293,10 +300,10 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
|
|
293
300
|
end
|
294
301
|
|
295
302
|
def isValidPayloadSize(documents,lmlogs_event,max_payload_size)
|
296
|
-
if (documents.to_json.bytesize + lmlogs_event.to_json.bytesize) > max_payload_size
|
303
|
+
if (documents.to_json.bytesize + lmlogs_event.to_json.bytesize) > max_payload_size
|
297
304
|
send_batch(documents)
|
298
305
|
documents = []
|
299
|
-
|
306
|
+
|
300
307
|
end
|
301
308
|
documents.push(lmlogs_event)
|
302
309
|
return documents
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'logstash-output-lmlogs'
|
3
|
-
s.version = '1.
|
3
|
+
s.version = '1.3.0'
|
4
4
|
s.licenses = ['Apache-2.0']
|
5
5
|
s.summary = "Logstash output plugin for LM Logs"
|
6
6
|
s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/devutils/rspec/spec_helper"
|
3
|
+
require "logstash/outputs/lmlogs"
|
4
|
+
require "logstash/event"
|
5
|
+
|
6
|
+
describe LogStash::Outputs::LMLogs do
|
7
|
+
|
8
|
+
let(:sample_lm_logs_event){{"message" => "hello this is log 1", "_lm.resourceId" => {"test.property" => "host1"}, "timestamp" => "2021-03-22T04:28:55.907121106Z"}}
|
9
|
+
|
10
|
+
def create_output_plugin_with_conf(conf)
|
11
|
+
return LogStash::Outputs::LMLogs.new(conf)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "with no auth specified" do
|
15
|
+
puts "auth test"
|
16
|
+
plugin = create_output_plugin_with_conf({
|
17
|
+
"portal_name" => "localhost"
|
18
|
+
})
|
19
|
+
expect { plugin.configure_auth() }.to raise_error(LogStash::ConfigurationError)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "access_key id is specified with no bearer" do
|
23
|
+
puts "auth test"
|
24
|
+
plugin = create_output_plugin_with_conf({
|
25
|
+
"portal_name" => "localhost",
|
26
|
+
"access_id" => "abcd",
|
27
|
+
"access_key" => "abcd"
|
28
|
+
})
|
29
|
+
plugin.configure_auth()
|
30
|
+
auth_string = plugin.generate_auth_string([sample_lm_logs_event])
|
31
|
+
|
32
|
+
expect(auth_string).to start_with("LMv1 abcd:")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "when access id /key not specified but bearer specified" do
|
36
|
+
plugin = create_output_plugin_with_conf({
|
37
|
+
"portal_name" => "localhost",
|
38
|
+
"access_id" => "abcd",
|
39
|
+
"bearer_token" => "abcd"
|
40
|
+
})
|
41
|
+
plugin.configure_auth()
|
42
|
+
auth_string = plugin.generate_auth_string([sample_lm_logs_event])
|
43
|
+
|
44
|
+
expect(auth_string).to eq("Bearer abcd")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "when access id /key bearer all specified, use lmv1" do
|
48
|
+
puts "auth test"
|
49
|
+
plugin = create_output_plugin_with_conf({
|
50
|
+
"portal_name" => "localhost",
|
51
|
+
"access_id" => "abcd",
|
52
|
+
"access_key" => "abcd",
|
53
|
+
"bearer_token" => "abcd"
|
54
|
+
})
|
55
|
+
plugin.configure_auth()
|
56
|
+
auth_string = plugin.generate_auth_string([sample_lm_logs_event])
|
57
|
+
|
58
|
+
expect(auth_string).to start_with("LMv1 abcd:")
|
59
|
+
end
|
60
|
+
end
|
data/spec/outputs/lmlogs_spec.rb
CHANGED
@@ -4,7 +4,7 @@ require "logstash/outputs/lmlogs"
|
|
4
4
|
require "logstash/event"
|
5
5
|
|
6
6
|
describe LogStash::Outputs::LMLogs do
|
7
|
-
let(:sample_event) { LogStash::Event.new("message" => "hello this is log"
|
7
|
+
let(:sample_event) { LogStash::Event.new("message" => "hello this is log","event" => {"sequence" => 0,"original" => "simple logstash msg from me running with proxy settings"})}
|
8
8
|
let(:client) { @lmlogs.client }
|
9
9
|
let(:sample_lm_logs_event){{"message" => "hello this is log 1", "_lm.resourceId" => {"test.property" => "host1"}, "timestamp" => "2021-03-22T04:28:55.907121106Z"}}
|
10
10
|
|
@@ -30,18 +30,19 @@ describe LogStash::Outputs::LMLogs do
|
|
30
30
|
@lmlogs.multi_receive([sample_event])
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
33
|
+
# TODO fix failing test case
|
34
|
+
# it "Batches multiple events and extracts metadata" do
|
35
|
+
# event1 = LogStash::Event.new("message" => "hello this is log 1", "host" => "host1")
|
36
|
+
# event2 = LogStash::Event.new("message" => "hello this is log 2", "host" => "host2")
|
37
|
+
# event3 = LogStash::Event.new("message" => "hello this is log 3", "host" => "host3")
|
38
|
+
# expect(client).to receive(:post).once.with("https://localhost.logicmonitor.com/rest/log/ingest",hash_including(body:
|
39
|
+
# [{ "host" => "host1", "message" => "hello this is log 1","@version":"1", "_lm.resourceId" => {"test.property" => "host1"}, "timestamp" => event1.timestamp.to_s,},
|
40
|
+
# {"host" => "host2","message" => "hello this is log 2","@version":"1", "_lm.resourceId" => {"test.property" => "host2"}, "timestamp" => event2.timestamp.to_s},
|
41
|
+
# {"host" => "host3","message" => "hello this is log 3","@version":"1", "_lm.resourceId" => {"test.property" => "host3"}, "timestamp" => event3.timestamp.to_s}
|
42
|
+
# ].to_json
|
43
|
+
# )).and_call_original
|
44
|
+
# @lmlogs.multi_receive([event1, event2, event3])
|
45
|
+
# end
|
45
46
|
|
46
47
|
it "Batches data of size batch_size" do
|
47
48
|
expect(client).to receive(:post).exactly(2).times.and_call_original
|
@@ -66,7 +67,7 @@ describe LogStash::Outputs::LMLogs do
|
|
66
67
|
document = [sample_lm_logs_event]
|
67
68
|
|
68
69
|
lm_logs_event = {"message" => "hello this is log 2", "_lm.resourceId" => {"test.property" => "host3"}, "timestamp" => "2021-03-22T04:28:55.909421106Z"}
|
69
|
-
|
70
|
+
|
70
71
|
document_expected = [sample_lm_logs_event,lm_logs_event]
|
71
72
|
expect(client).to receive(:post).exactly(0).times.and_call_original
|
72
73
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-output-lmlogs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- LogicMonitor
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -91,6 +91,7 @@ files:
|
|
91
91
|
- README.md
|
92
92
|
- lib/logstash/outputs/lmlogs.rb
|
93
93
|
- logstash-output-lmlogs.gemspec
|
94
|
+
- spec/outputs/auth_spec.rb
|
94
95
|
- spec/outputs/lmlogs_spec.rb
|
95
96
|
homepage: https://www.logicmonitor.com
|
96
97
|
licenses:
|
@@ -114,9 +115,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
115
|
- !ruby/object:Gem::Version
|
115
116
|
version: '0'
|
116
117
|
requirements: []
|
117
|
-
rubygems_version: 3.
|
118
|
+
rubygems_version: 3.2.33
|
118
119
|
signing_key:
|
119
120
|
specification_version: 4
|
120
121
|
summary: Logstash output plugin for LM Logs
|
121
122
|
test_files:
|
123
|
+
- spec/outputs/auth_spec.rb
|
122
124
|
- spec/outputs/lmlogs_spec.rb
|