logstash-output-lmlogs 1.3.0 → 2.0.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: 870bd26e9fabeb697cb8dd8f66eeb7f243b4be3fcf51c0d3babb81260a08b3d9
4
- data.tar.gz: 548fff67d397ef9a6c51a2bebb0c4f44d2b3decd57faa801bd9ac2e1048edad2
3
+ metadata.gz: 46b4784b47b720c638e2f6cb53ace887c3ff3bd821cc27ca675fc3bf6b5b3325
4
+ data.tar.gz: 2dd4c277e4b769d4580ea1474d00f058d2f08f1d718da6e715c51ab16f722679
5
5
  SHA512:
6
- metadata.gz: 504cdc43d302a8d504a38627e3b914e8514331ae889dbcfba7fa3f0da6f010aeb09aa19437f5d32e73e100db4d0f839f9c182eb4135b78cfb1d538a6ea0f4314
7
- data.tar.gz: 78a8b8b391c4887bfa5a06b12d044d03c9d3b9f2cfdc9231ae5a9d0a70ac28d824e59ce493cf8a4f3d2fc7675ecd0a7ce8b7d71c60fa8fc57664a7937793ad07
6
+ metadata.gz: 118161034fbd6b10b946449a75ccabc6fcce733006824711bdbcde2fff864f65ac249bd1de2f78600e975e71f47740881e946c4f2335a82956e6a8b130f44af5
7
+ data.tar.gz: f28a74d295e3f14bca4bfed4389c5dd32cfaaecb8f5b550168f2542494b0876c50b95d42661d101879284f9a7f532a74551b7fa1989abf83289b046f210e33de
data/CHANGELOG.md CHANGED
@@ -7,8 +7,12 @@
7
7
  ## 1.1.0
8
8
  - Disable mfa for gem push
9
9
  ## 1.2.0
10
- - Add metadata by default to every log
10
+ - Add metadata by default to every log
11
11
  ## 1.2.1
12
12
  - Fix ensuring metadata exists before deleting the original while forwarding to lm-logs
13
13
  ## 1.3.0
14
- - Add bearer token support for authentication with Logicmonitor
14
+ - Add bearer token support for authentication with Logicmonitor
15
+ ## 1.3.1
16
+ - Fix user agent populated in headers
17
+ ## 2.0.0
18
+ - Dont send event metadata by default. Add config include_metadata_keys for including custom metadata
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/logstash-output-lmlogs.svg)](https://badge.fury.io/rb/logstash-output-lmlogs)
2
2
 
3
- This plugin sends Logstash events to the [Logicmonitor Logs](https://www.logicmonitor.com)
3
+ This plugin sends Logstash events to the [Logicmonitor Logs](https://www.logicmonitor.com)
4
4
 
5
5
  # Getting started
6
6
 
@@ -20,6 +20,7 @@ output {
20
20
  }
21
21
  }
22
22
  ```
23
+ You would need either `access_id` and `access_id` both or `bearer_token` for authentication with Logicmonitor.
23
24
 
24
25
 
25
26
 
@@ -27,27 +28,28 @@ output {
27
28
 
28
29
  | Option | Description| Default |
29
30
  | --- | --- | --- |
30
- | batch_size | Event batch size to send to LM Logs.| 100 |
31
+ | batch_size | Event batch size to send to LM Logs.| 100 |
31
32
  | message_key | Key that will be used by the plugin as the system key | "message" |
32
33
  | lm_property | Key that will be used by LM to match resource based on property | "system.hostname" |
33
34
  | keep_timestamp | If false, LM Logs will use the ingestion timestamp as the event timestamp | true |
34
35
  | timestamp_is_key | If true, LM Logs will use a specified key as the event timestamp | false |
35
36
  | timestamp_key | If timestamp_is_key is set, LM Logs will use this key in the event as the timestamp | "logtimestamp" |
36
- | include_metadata | If false, the metadata fields will not be sent to LM Logs | true |
37
+ | include_metadata | If true, all metadata fields will be sent to LM Logs | false |
38
+ | include_metadata_keys | Array of json keys for which plugin looks for these keys and adds as event meatadata. A dot "." can be used to add nested subjson. If config `include_metadata` is set to true, all metadata will be sent regardless of this config. | [] |
37
39
 
38
40
  See the [source code](lib/logstash/outputs/lmlogs.rb) for the full list of options
39
41
 
40
42
  The syntax for `message_key` and `source_key` values are available in the [Logstash Event API Documentation](https://www.elastic.co/guide/en/logstash/current/event-api.html)
41
43
 
42
- ## Known issues
44
+ ## Known issues
43
45
  - Installation of the plugin fails on Logstash 6.2.1.
44
-
45
-
46
+
47
+
46
48
  ## Contributing
47
-
49
+
48
50
  Bug reports and pull requests are welcome. This project is intended to
49
51
  be a safe, welcoming space for collaboration.
50
-
52
+
51
53
  ## Development
52
-
54
+
53
55
  We use docker to build the plugin. You can build it by running `docker-compose run jruby gem build logstash-output-lmlogs.gemspec `
@@ -8,6 +8,7 @@ require 'date'
8
8
  require 'base64'
9
9
  require 'openssl'
10
10
  require 'manticore'
11
+ require_relative "version"
11
12
 
12
13
  # An example output that does nothing.
13
14
  class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
@@ -94,7 +95,7 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
94
95
  config :access_id, :validate => :string, :required => false, :default => nil
95
96
 
96
97
  # Include/Exclude metadata from sending to LM Logs
97
- config :include_metadata, :validate => :boolean, :default => true
98
+ config :include_metadata, :validate => :boolean, :default => false
98
99
 
99
100
  # Password to use for HTTP auth
100
101
  config :access_key, :validate => :password, :required => false, :default => nil
@@ -102,6 +103,9 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
102
103
  # Use bearer token instead of access key/id for authentication.
103
104
  config :bearer_token, :validate => :password, :required => false, :default => nil
104
105
 
106
+ # json keys for which plugin looks for these keys and adds as event meatadata. A dot "." can be used to add nested subjson.
107
+ config :include_metadata_keys, :validate => :array, :required => false, :default => []
108
+
105
109
  @@MAX_PAYLOAD_SIZE = 8*1024*1024
106
110
 
107
111
  # For developer debugging.
@@ -116,6 +120,14 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
116
120
  logger.info("Max Payload Size: ",
117
121
  :size => @@MAX_PAYLOAD_SIZE)
118
122
  configure_auth
123
+
124
+ @final_metadata_keys = Hash.new
125
+ if @include_metadata_keys.any?
126
+ include_metadata_keys.each do | nested_key |
127
+ @final_metadata_keys[nested_key] = nested_key.to_s.split('.')
128
+ end
129
+ end
130
+
119
131
  end # def register
120
132
 
121
133
  def client_config
@@ -164,12 +176,12 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
164
176
  if @access_id == nil || @access_key.value == nil
165
177
  @logger.info "Access Id or access key null. Using bearer token for authentication."
166
178
  @use_bearer_instead_of_lmv1 = true
167
- end
168
- if @use_bearer_instead_of_lmv1 && @bearer_token.value == nil
179
+ end
180
+ if @use_bearer_instead_of_lmv1 && @bearer_token.value == nil
169
181
  @logger.error "Bearer token not specified. Either access_id and access_key both or bearer_token must be specified for authentication with Logicmonitor."
170
182
  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
183
  end
172
- end
184
+ end
173
185
  def generate_auth_string(body)
174
186
  if @use_bearer_instead_of_lmv1
175
187
  return "Bearer #{@bearer_token.value}"
@@ -196,7 +208,7 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
196
208
  :body => body,
197
209
  :headers => {
198
210
  "Content-Type" => "application/json",
199
- "User-Agent" => "LM Logs Logstash Plugin",
211
+ "User-Agent" => "lm-logs-logstash/" + LmLogsLogstashPlugin::VERSION,
200
212
  "Authorization" => "#{auth_string}"
201
213
  }
202
214
  })
@@ -265,34 +277,48 @@ class LogStash::Outputs::LMLogs < LogStash::Outputs::Base
265
277
  events.each_slice(@batch_size) do |chunk|
266
278
  documents = []
267
279
  chunk.each do |event|
268
- event_json = JSON.parse(event.to_json)
269
- lmlogs_event = {}
270
-
271
- if @include_metadata
272
- lmlogs_event = event_json
273
- lmlogs_event.delete("@timestamp") # remove redundant timestamp field
274
- if lmlogs_event.dig("event", "original") != nil
275
- lmlogs_event["event"].delete("original") # remove redundant log field
276
- end
277
- end
278
280
 
279
- lmlogs_event["message"] = event.get(@message_key).to_s
280
- lmlogs_event["_lm.resourceId"] = {}
281
- lmlogs_event["_lm.resourceId"]["#{@lm_property}"] = event.get(@property_key.to_s)
281
+ documents = isValidPayloadSize(documents, processEvent(event), @@MAX_PAYLOAD_SIZE)
282
+ end
283
+ send_batch(documents)
284
+ end
285
+ end
282
286
 
283
- if @keep_timestamp
284
- lmlogs_event["timestamp"] = event.get("@timestamp")
285
- end
286
287
 
287
- if @timestamp_is_key
288
- lmlogs_event["timestamp"] = event.get(@timestamp_key.to_s)
288
+ def processEvent(event)
289
+ event_json = JSON.parse(event.to_json)
290
+ lmlogs_event = {}
291
+
292
+ if @include_metadata
293
+ lmlogs_event = event_json
294
+ lmlogs_event.delete("@timestamp") # remove redundant timestamp field
295
+ if lmlogs_event.dig("event", "original") != nil
296
+ lmlogs_event["event"].delete("original") # remove redundant log field
297
+ end
298
+ elsif @final_metadata_keys
299
+ @final_metadata_keys.each do | key, value |
300
+ nestedVal = event_json
301
+ value.each { |x| nestedVal = nestedVal[x] }
302
+ if nestedVal != nil
303
+ lmlogs_event[key] = nestedVal
289
304
  end
305
+ end
306
+ end
290
307
 
291
- documents = isValidPayloadSize(documents,lmlogs_event,@@MAX_PAYLOAD_SIZE)
308
+ lmlogs_event["message"] = event.get(@message_key).to_s
309
+ lmlogs_event["_lm.resourceId"] = {}
310
+ lmlogs_event["_lm.resourceId"]["#{@lm_property}"] = event.get(@property_key.to_s)
292
311
 
293
- end
294
- send_batch(documents)
312
+ if @keep_timestamp
313
+ lmlogs_event["timestamp"] = event.get("@timestamp")
314
+ end
315
+
316
+ if @timestamp_is_key
317
+ lmlogs_event["timestamp"] = event.get(@timestamp_key.to_s)
295
318
  end
319
+
320
+ return lmlogs_event
321
+
296
322
  end
297
323
 
298
324
  def log_failure(message, opts)
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LmLogsLogstashPlugin
4
+ VERSION = '2.0.0'
5
+ end
@@ -1,6 +1,14 @@
1
+
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require "logstash/outputs/version.rb"
6
+
7
+
8
+
1
9
  Gem::Specification.new do |s|
2
10
  s.name = 'logstash-output-lmlogs'
3
- s.version = '1.3.0'
11
+ s.version = LmLogsLogstashPlugin::VERSION
4
12
  s.licenses = ['Apache-2.0']
5
13
  s.summary = "Logstash output plugin for LM Logs"
6
14
  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"
@@ -25,4 +33,5 @@ Gem::Specification.new do |s|
25
33
  s.add_runtime_dependency 'manticore', '>= 0.5.2', '< 1.0.0'
26
34
 
27
35
  s.add_development_dependency 'logstash-devutils'
36
+ s.add_development_dependency 'hashdiff', '>= 1.0.0'
28
37
  end
@@ -0,0 +1,86 @@
1
+ # encoding: utf-8
2
+ require "logstash/devutils/rspec/spec_helper"
3
+ require "logstash/outputs/lmlogs"
4
+ require "logstash/event"
5
+ require "hashdiff"
6
+
7
+
8
+ describe LogStash::Outputs::LMLogs do
9
+
10
+
11
+ let(:logstash_event) {LogStash::Event.new("message" => "hello this is log 1",
12
+ "host" => "host1",
13
+ "nested1" => {"nested2" => {"nested3" => "value"},
14
+ "nested2a" => {"nested3a" => {"nested4" => "valueA"}},
15
+ "nested2b" => {"nested3b" => "value"}
16
+ },
17
+ "nested1_" => "value",
18
+ "nested" => {"nested2" => {"nested3" => "value",
19
+ "nested3b" => "value"},
20
+ "nested_ignored" => "somevalue"
21
+ }
22
+ )}
23
+ let(:sample_lm_logs_event){{"message" => "hello this is log 1", "_lm.resourceId" => {"test.property" => "host1"}, "timestamp" => "2021-03-22T04:28:55.907121106Z"}}
24
+ let(:include_metadata_keys) {["host", "nested1.nested2.nested3", "nested1.nested2a", "nested.nested2" ]}
25
+
26
+ def create_output_plugin_with_conf(conf)
27
+ return LogStash::Outputs::LMLogs.new(conf)
28
+ end
29
+
30
+ def check_same_hash(h1,h2)
31
+
32
+ end
33
+
34
+ it "default behaviour" do
35
+ puts "default behaviour"
36
+ plugin = create_output_plugin_with_conf({
37
+ "portal_name" => "localhost",
38
+ "access_id" => "abcd",
39
+ "access_key" => "abcd",
40
+ "lm_property" => "system.hostname",
41
+ "property_key" => "host"
42
+ })
43
+ constructed_event = plugin.processEvent(logstash_event)
44
+ expected_event = {
45
+ "message" => "hello this is log 1",
46
+ "timestamp" => logstash_event.timestamp,
47
+ "_lm.resourceId" => {"system.hostname" => "host1"},
48
+
49
+ }
50
+ puts " actual : #{constructed_event} \n expected : #{expected_event}"
51
+
52
+ expect(Hashdiff.diff(constructed_event,expected_event)).to eq([])
53
+ end
54
+
55
+ it "with include_metadata set to true" do
56
+ puts "with include_metadata set to true"
57
+ plugin = create_output_plugin_with_conf({
58
+ "portal_name" => "localhost",
59
+ "access_id" => "abcd",
60
+ "access_key" => "abcd",
61
+ "lm_property" => "system.hostname",
62
+ "property_key" => "host",
63
+ "include_metadata" => true
64
+ })
65
+ constructed_event = plugin.processEvent(logstash_event)
66
+ expected_event = {
67
+ "message" => "hello this is log 1",
68
+ "timestamp" => logstash_event.timestamp,
69
+ "@version" => "1",
70
+ "_lm.resourceId" => {"system.hostname" => "host1"},
71
+ "host" => "host1",
72
+ "nested1" => {"nested2" => {"nested3" => "value"},
73
+ "nested2a" => {"nested3a" => {"nested4" => "valueA"}},
74
+ "nested2b" => {"nested3b" => "value"}
75
+ },
76
+ "nested1_" => "value",
77
+ "nested" => {"nested2" => {"nested3" => "value",
78
+ "nested3b" => "value"},
79
+ "nested_ignored" => "somevalue"
80
+ }
81
+ }
82
+ puts " actual : #{constructed_event} \n expected : #{expected_event}"
83
+ puts " hash diff : #{Hashdiff.diff(constructed_event,expected_event)}"
84
+ expect(Hashdiff.diff(constructed_event,expected_event)).to eq([])
85
+ end
86
+ end
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.3.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - LogicMonitor
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-06 00:00:00.000000000 Z
11
+ date: 2023-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -78,6 +78,20 @@ dependencies:
78
78
  - - ">="
79
79
  - !ruby/object:Gem::Version
80
80
  version: '0'
81
+ - !ruby/object:Gem::Dependency
82
+ requirement: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 1.0.0
87
+ name: hashdiff
88
+ prerelease: false
89
+ type: :development
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 1.0.0
81
95
  description: This gem is a Logstash plugin required to be installed on top of the
82
96
  Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This
83
97
  gem is not a stand-alone program
@@ -90,9 +104,11 @@ files:
90
104
  - Gemfile
91
105
  - README.md
92
106
  - lib/logstash/outputs/lmlogs.rb
107
+ - lib/logstash/outputs/version.rb
93
108
  - logstash-output-lmlogs.gemspec
94
109
  - spec/outputs/auth_spec.rb
95
110
  - spec/outputs/lmlogs_spec.rb
111
+ - spec/outputs/metadata_spec.rb
96
112
  homepage: https://www.logicmonitor.com
97
113
  licenses:
98
114
  - Apache-2.0
@@ -122,3 +138,4 @@ summary: Logstash output plugin for LM Logs
122
138
  test_files:
123
139
  - spec/outputs/auth_spec.rb
124
140
  - spec/outputs/lmlogs_spec.rb
141
+ - spec/outputs/metadata_spec.rb