logstash-output-scalyr 0.1.19.beta → 0.1.23.beta

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/Gemfile +2 -2
  4. data/README.md +7 -1
  5. data/lib/logstash/outputs/scalyr.rb +97 -61
  6. data/lib/scalyr/common/util.rb +71 -27
  7. data/lib/scalyr/constants.rb +1 -1
  8. data/logstash-output-scalyr.gemspec +1 -1
  9. data/spec/logstash/outputs/scalyr_integration_spec.rb +8 -2
  10. data/spec/logstash/outputs/scalyr_spec.rb +40 -2
  11. data/spec/scalyr/common/util_spec.rb +253 -0
  12. data/vendor/bundle/jruby/2.5.0/bin/htmldiff +1 -1
  13. data/vendor/bundle/jruby/2.5.0/bin/ldiff +1 -1
  14. data/vendor/bundle/jruby/2.5.0/cache/manticore-0.7.1-java.gem +0 -0
  15. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/APACHE-LICENSE-2.0.txt +0 -0
  16. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/CHANGELOG.md +12 -3
  17. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/Gemfile +2 -1
  18. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/LICENSE.txt +0 -0
  19. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/README.md +17 -4
  20. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/Rakefile +0 -0
  21. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/ext/manticore/org/manticore/HttpDeleteWithEntity.java +0 -0
  22. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/ext/manticore/org/manticore/HttpGetWithEntity.java +0 -0
  23. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/ext/manticore/org/manticore/Manticore.java +0 -0
  24. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/gem-public_cert.pem +0 -0
  25. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/commons-codec/commons-codec/1.10/commons-codec-1.10.jar +0 -0
  26. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/commons-logging/commons-logging/1.2/commons-logging-1.2.jar +0 -0
  27. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/faraday/adapter/manticore.rb +1 -6
  28. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/manticore/client/proxies.rb +0 -0
  29. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/manticore/client.rb +24 -16
  30. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/manticore/cookie.rb +0 -0
  31. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/manticore/facade.rb +0 -0
  32. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/manticore/java_extensions.rb +0 -0
  33. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/manticore/response.rb +12 -12
  34. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/manticore/stubbed_response.rb +0 -0
  35. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/manticore/version.rb +1 -1
  36. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/manticore.rb +26 -2
  37. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/manticore_jars.rb +0 -0
  38. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/org/apache/httpcomponents/httpclient/4.5.2/httpclient-4.5.2.jar +0 -0
  39. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/org/apache/httpcomponents/httpcore/4.4.4/httpcore-4.4.4.jar +0 -0
  40. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/org/apache/httpcomponents/httpmime/4.5.2/httpmime-4.5.2.jar +0 -0
  41. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/lib/org/manticore/manticore-ext.jar +0 -0
  42. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/manticore.gemspec +4 -2
  43. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/spec/manticore/client_proxy_spec.rb +0 -0
  44. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/spec/manticore/client_spec.rb +15 -3
  45. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/spec/manticore/cookie_spec.rb +0 -0
  46. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/spec/manticore/facade_spec.rb +0 -0
  47. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/spec/manticore/response_spec.rb +1 -1
  48. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/spec/manticore/stubbed_response_spec.rb +0 -0
  49. data/vendor/bundle/jruby/2.5.0/gems/{manticore-0.6.4-java → manticore-0.7.1-java}/spec/spec_helper.rb +0 -0
  50. data/vendor/bundle/jruby/2.5.0/specifications/{manticore-0.6.4-java.gemspec → manticore-0.7.1-java.gemspec} +10 -9
  51. metadata +39 -39
  52. data/vendor/bundle/jruby/2.5.0/cache/manticore-0.6.4-java.gem +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '084d41a09e7ef86214868f26a97639169df8982d9488eb827d337ef53f02fc07'
4
- data.tar.gz: 5bd3b17804c60044901d2f40c40419c119e680f7ac4a4ffc543701a885cb0c2e
3
+ metadata.gz: 8e2757da74eb03ea09a88597ed713db01bc050e17c31c771558bdb16a80ca40e
4
+ data.tar.gz: 1bc8519d1b30aea135d66b8b9ecfb632f688fd62abd58cd3b91cc92c4ad8957f
5
5
  SHA512:
6
- metadata.gz: 837bd2d4d142f31bcd30494175731818de9f60f9f39ebc13cf0ae92b36e58ad4b6d288ba2f92109323f096d30a1774334651907b07e1d1310f6b42dd24698b2e
7
- data.tar.gz: 221e47feab585a99dc69b475f446f9a9b4f9d2bd91ffd60753886438c348e0139618afa46f3889180aba68582ed9532376ee5449fb0cf91bb05cbb796c11a08c
6
+ metadata.gz: 327a3e2ba020f3166b0c435700bdfedf4f96598a352f1f66f45fe9e671a053ee684aa812d686a4d58b5dd9f319e8b0f87e2ea8290d876e504b8416a8010795ed
7
+ data.tar.gz: 1ba44520daddda5c17da810221063ce815af082645ae3fd12e76b031247ff8a13cb3e7dab4fbf69e84e5a876605290702785cc17639de69435f0b780a74691f9
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Beta
2
2
 
3
+ ## 0.1.23.beta
4
+ - Add testing support for disabling estimation of serialized event size for each event in the batch.
5
+
6
+ ## 0.1.22.beta
7
+ - Add new plugin metric for tracking the duration of ``build_multi_event_request_array`` method.
8
+ - Update internal dependencies (``manticore``) to latest stable version.
9
+
10
+ ## 0.1.21.beta
11
+ - Fix issue with iterative flattening function when dealing with empty collections.
12
+
13
+ ## 0.1.20.beta
14
+ - Rewrite flattening function to no longer be recursive, to help avoid maxing out the stack.
15
+ - Added a configurable value `flattening_max_key_count` to create a limit on how large of a record we can flatten.
16
+ It limits the maximum amount of keys we can have in the final flattened record. Defaults to unlimited.
17
+
3
18
  ## 0.1.19.beta
4
19
  - Undo a change to nested value flattening functionality to keep existing formatting. This change can be re-enabled
5
20
  by setting the `fix_deep_flattening_delimiters` configuration option to true.
data/Gemfile CHANGED
@@ -16,5 +16,5 @@ end
16
16
 
17
17
  gem 'pry'
18
18
  gem 'pry-nav'
19
- gem 'quantile'
20
- gem 'manticore', platform: :jruby
19
+ gem 'quantile', '~> 0.2.1'
20
+ gem 'manticore', '~> 0.7.1', platform: :jruby
data/README.md CHANGED
@@ -10,7 +10,7 @@ You can view documentation for this plugin [on the Scalyr website](https://app.s
10
10
  # Quick start
11
11
 
12
12
  1. Build the gem, run `gem build logstash-output-scalyr.gemspec`
13
- 2. Install the gem into a Logstash installation, run `/usr/share/logstash/bin/logstash-plugin install logstash-output-scalyr-0.1.19.beta.gem` or follow the latest official instructions on working with plugins from Logstash.
13
+ 2. Install the gem into a Logstash installation, run `/usr/share/logstash/bin/logstash-plugin install logstash-output-scalyr-0.1.22.beta.gem` or follow the latest official instructions on working with plugins from Logstash.
14
14
  3. Configure the output plugin (e.g. add it to a pipeline .conf)
15
15
  4. Restart Logstash
16
16
 
@@ -321,6 +321,12 @@ If you want to run just the unit tests, you can run the command displayed below.
321
321
  bundle exec rspec spec/logstash/outputs/scalyr_spec.rb spec/scalyr/common/util_spec.rb
322
322
  ```
323
323
 
324
+ Or to run a single test function defined on line XXX
325
+
326
+ ```bash
327
+ bundle exec rspec spec/scalyr/common/util_spec.rb:XXX
328
+ ```
329
+
324
330
  ## Instrumentation and metrics
325
331
 
326
332
  By default, plugin logs a special line with metrics to Scalyr every 5 minutes. This line contains
@@ -71,6 +71,7 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
71
71
  config :flatten_nested_values_delimiter, :validate => :string, :default => "_"
72
72
  config :flatten_nested_arrays, :validate => :boolean, :default => true
73
73
  config :fix_deep_flattening_delimiters, :validate => :boolean, :default => false
74
+ config :flattening_max_key_count, :validate => :number, :default => -1
74
75
 
75
76
  # If true, the 'tags' field will be flattened into key-values where each key is a tag and each value is set to
76
77
  # :flat_tag_value
@@ -139,11 +140,17 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
139
140
  # Whether or not to create fresh quantile estimators after a status send. Depending on what you want to gather from
140
141
  # these stas this might be wanted or not.
141
142
  config :flush_quantile_estimates_on_status_send, :validate => :boolean, :default => false
142
-
143
+
143
144
  # Causes this plugin to act as if it successfully uploaded the logs, while actually returning as quickly as possible
144
145
  # after no work being done.
145
146
  config :noop_mode, :validate => :boolean, :default => false
146
147
 
148
+ # Set to true to disable estimiating the size of each serialized event to make sure we don't go over the max request
149
+ # size (5.5) and split batch into multiple Scalyr requests, if needed. Since this estimation is not "free", especially
150
+ # for large batches, it may make sense to disable this option when logstash batch size is configured in a way that
151
+ # Scalyr single request limit won't be reached.
152
+ config :estimate_each_event_size, :validate => :boolean, :default => true
153
+
147
154
  # Manticore related options
148
155
  config :http_connect_timeout, :validate => :number, :default => 10
149
156
  config :http_socket_timeout, :validate => :number, :default => 10
@@ -288,6 +295,7 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
288
295
  # Convenience method to create a fresh quantile estimator
289
296
  def get_new_metrics
290
297
  return {
298
+ :build_multi_duration_secs => Quantile::Estimator.new,
291
299
  :multi_receive_duration_secs => Quantile::Estimator.new,
292
300
  :multi_receive_event_count => Quantile::Estimator.new,
293
301
  :event_attributes_count => Quantile::Estimator.new,
@@ -312,17 +320,21 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
312
320
  return events if @noop_mode
313
321
 
314
322
  begin
323
+ records_count = events.to_a.length
324
+
325
+ # We also time the duration of the build_multi_event_request_array method. To avoid locking twice,
326
+ # we store the duration value here and record metric at the end.
315
327
  start_time = Time.now.to_f
316
328
 
317
329
  multi_event_request_array = build_multi_event_request_array(events)
318
- # Loop over all array of multi-event requests, sending each multi-event to Scalyr
330
+ build_multi_duration_secs = Time.now.to_f - start_time
319
331
 
332
+ # Loop over all array of multi-event requests, sending each multi-event to Scalyr
320
333
  sleep_interval = @retry_initial_interval
321
334
  batch_num = 1
322
335
  total_batches = multi_event_request_array.length unless multi_event_request_array.nil?
323
336
 
324
337
  result = []
325
- records_count = events.to_a.length
326
338
 
327
339
  while !multi_event_request_array.to_a.empty?
328
340
  multi_event_request = multi_event_request_array.pop
@@ -429,6 +441,7 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
429
441
  if records_count > 0
430
442
  @stats_lock.synchronize do
431
443
  @multi_receive_statistics[:total_multi_receive_secs] += (Time.now.to_f - start_time)
444
+ @plugin_metrics[:build_multi_duration_secs].observe(build_multi_duration_secs)
432
445
  @plugin_metrics[:multi_receive_duration_secs].observe(Time.now.to_f - start_time)
433
446
  @plugin_metrics[:multi_receive_event_count].observe(records_count)
434
447
  @plugin_metrics[:batches_per_multi_receive].observe(total_batches)
@@ -633,7 +646,11 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
633
646
  # flatten record
634
647
  if @flatten_nested_values
635
648
  start_time = Time.now.to_f
636
- record = Scalyr::Common::Util.flatten(record, delimiter=@flatten_nested_values_delimiter, flatten_arrays=@flatten_nested_arrays, fix_deep_flattening_delimiters=@fix_deep_flattening_delimiters)
649
+ begin
650
+ record = Scalyr::Common::Util.flatten(record, delimiter=@flatten_nested_values_delimiter, flatten_arrays=@flatten_nested_arrays, fix_deep_flattening_delimiters=@fix_deep_flattening_delimiters, max_key_count=@flattening_max_key_count)
651
+ rescue Scalyr::Common::Util::MaxKeyCountError => e
652
+ @logger.warn("Error while flattening record", :error_message => e.message, :sample_keys => e.sample_keys)
653
+ end
637
654
  end_time = Time.now.to_f
638
655
  flatten_nested_values_duration = end_time - start_time
639
656
  end
@@ -661,67 +678,74 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
661
678
  scalyr_event[:log] = logs_ids[log_identifier]
662
679
  end
663
680
 
664
- # get json string of event to keep track of how many bytes we are sending
665
- begin
666
- event_json = scalyr_event.to_json
667
- log_json = nil
668
- if add_log
669
- log_json = logs[log_identifier].to_json
670
- end
671
- rescue JSON::GeneratorError, Encoding::UndefinedConversionError => e
672
- @logger.warn "#{e.class}: #{e.message}"
673
-
674
- # Send the faulty event to a label @ERROR block and allow to handle it there (output to exceptions file for ex)
675
- # TODO
676
- # atime = Fluent::EventTime.new( sec, nsec )
677
- # router.emit_error_event(serverHost, time, record, e)
678
-
679
- scalyr_event[:attrs].each do |key, value|
680
- @logger.debug "\t#{key} (#{value.encoding.name}): '#{value}'"
681
- scalyr_event[:attrs][key] = value.encode(
682
- "UTF-8", :invalid => :replace, :undef => :replace, :replace => "<?>"
683
- ).force_encoding('UTF-8')
684
- end
685
- event_json = scalyr_event.to_json
686
- rescue Java::JavaLang::ClassCastException => e
687
- # Most likely we ran into the issue described here: https://github.com/flori/json/issues/336
688
- # Because of the version of jruby logstash works with we don't have the option to just update this away,
689
- # so if we run into it we convert bignums into strings so we can get the data in at least.
690
- # This is fixed in JRuby 9.2.7, which includes json 2.2.0
691
- @logger.warn("Error serializing events to JSON, likely due to the presence of Bignum values. Converting Bignum values to strings.")
692
- @stats_lock.synchronize do
693
- @multi_receive_statistics[:total_java_class_cast_errors] += 1
681
+ if @estimate_each_event_size
682
+ # get json string of event to keep track of how many bytes we are sending
683
+ begin
684
+ event_json = scalyr_event.to_json
685
+ log_json = nil
686
+ if add_log
687
+ log_json = logs[log_identifier].to_json
688
+ end
689
+ rescue JSON::GeneratorError, Encoding::UndefinedConversionError => e
690
+ @logger.warn "#{e.class}: #{e.message}"
691
+
692
+ # Send the faulty event to a label @ERROR block and allow to handle it there (output to exceptions file for ex)
693
+ # TODO
694
+ # atime = Fluent::EventTime.new( sec, nsec )
695
+ # router.emit_error_event(serverHost, time, record, e)
696
+
697
+ scalyr_event[:attrs].each do |key, value|
698
+ @logger.debug "\t#{key} (#{value.encoding.name}): '#{value}'"
699
+ scalyr_event[:attrs][key] = value.encode(
700
+ "UTF-8", :invalid => :replace, :undef => :replace, :replace => "<?>"
701
+ ).force_encoding('UTF-8')
702
+ end
703
+ event_json = scalyr_event.to_json
704
+ rescue Java::JavaLang::ClassCastException => e
705
+ # Most likely we ran into the issue described here: https://github.com/flori/json/issues/336
706
+ # Because of the version of jruby logstash works with we don't have the option to just update this away,
707
+ # so if we run into it we convert bignums into strings so we can get the data in at least.
708
+ # This is fixed in JRuby 9.2.7, which includes json 2.2.0
709
+ @logger.warn("Error serializing events to JSON, likely due to the presence of Bignum values. Converting Bignum values to strings.")
710
+ @stats_lock.synchronize do
711
+ @multi_receive_statistics[:total_java_class_cast_errors] += 1
712
+ end
713
+ Scalyr::Common::Util.convert_bignums(scalyr_event)
714
+ event_json = scalyr_event.to_json
715
+ log_json = nil
716
+ if add_log
717
+ log_json = logs[log_identifier].to_json
718
+ end
694
719
  end
695
- Scalyr::Common::Util.convert_bignums(scalyr_event)
696
- event_json = scalyr_event.to_json
697
- log_json = nil
698
- if add_log
699
- log_json = logs[log_identifier].to_json
720
+
721
+ # generate new request if json size of events in the array exceed maximum request buffer size
722
+ append_event = true
723
+ add_bytes = event_json.bytesize
724
+ if log_json
725
+ add_bytes = add_bytes + log_json.bytesize
700
726
  end
701
- end
702
727
 
703
- # generate new request if json size of events in the array exceed maximum request buffer size
704
- append_event = true
705
- add_bytes = event_json.bytesize
706
- if log_json
707
- add_bytes = add_bytes + log_json.bytesize
708
- end
709
- if total_bytes + add_bytes > @max_request_buffer
710
- # make sure we always have at least one event
711
- if scalyr_events.size == 0
712
- scalyr_events << scalyr_event
713
- l_events << l_event
714
- append_event = false
728
+ if total_bytes + add_bytes > @max_request_buffer
729
+ # make sure we always have at least one event
730
+ if scalyr_events.size == 0
731
+ scalyr_events << scalyr_event
732
+ l_events << l_event
733
+ append_event = false
734
+ end
735
+
736
+ multi_event_request = self.create_multi_event_request(scalyr_events, l_events, current_threads, logs)
737
+ multi_event_request_array << multi_event_request
738
+
739
+ total_bytes = 0
740
+ current_threads = Hash.new
741
+ logs = Hash.new
742
+ logs_ids = Hash.new
743
+ scalyr_events = Array.new
744
+ l_events = Array.new
715
745
  end
716
- multi_event_request = self.create_multi_event_request(scalyr_events, l_events, current_threads, logs)
717
- multi_event_request_array << multi_event_request
718
-
719
- total_bytes = 0
720
- current_threads = Hash.new
721
- logs = Hash.new
722
- logs_ids = Hash.new
723
- scalyr_events = Array.new
724
- l_events = Array.new
746
+ else
747
+ # If size estimation is disabled we simply append the event and handle splitting later on (if needed)
748
+ append_event = true
725
749
  end
726
750
 
727
751
  # if we haven't consumed the current event already
@@ -798,6 +822,14 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
798
822
  end
799
823
  end_time = Time.now.to_f
800
824
  serialization_duration = end_time - start_time
825
+
826
+ serialized_request_size = serialized_body.bytesize
827
+
828
+ if serialized_request_size >= @max_request_buffer
829
+ # TODO: If we end up here is estimate config opsion is false, split the request here into multiple ones
830
+ @logger.warn("Serialized request size (#{serialized_request_size}) is larger than max_request_buffer (#{max_request_buffer})!")
831
+ end
832
+
801
833
  {
802
834
  :body => serialized_body, :record_count => scalyr_events.size, :serialization_duration => serialization_duration,
803
835
  :logstash_events => logstash_events
@@ -811,6 +843,10 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
811
843
  @stats_lock.synchronize do
812
844
  current_stats = @multi_receive_statistics.clone
813
845
 
846
+ current_stats[:build_multi_duration_secs_p50] = @plugin_metrics[:build_multi_duration_secs].query(0.5)
847
+ current_stats[:build_multi_duration_secs_p90] = @plugin_metrics[:build_multi_duration_secs].query(0.9)
848
+ current_stats[:build_multi_duration_secs_p99] = @plugin_metrics[:build_multi_duration_secs].query(0.99)
849
+
814
850
  current_stats[:multi_receive_duration_p50] = @plugin_metrics[:multi_receive_duration_secs].query(0.5)
815
851
  current_stats[:multi_receive_duration_p90] = @plugin_metrics[:multi_receive_duration_secs].query(0.9)
816
852
  current_stats[:multi_receive_duration_p99] = @plugin_metrics[:multi_receive_duration_secs].query(0.99)
@@ -1,52 +1,96 @@
1
1
  module Scalyr; module Common; module Util;
2
2
 
3
+ class MaxKeyCountError < StandardError
4
+ attr_reader :message, :sample_keys
5
+
6
+ def initialize(message, sample_keys)
7
+ @message = message
8
+ @sample_keys = sample_keys
9
+ end
10
+ end
3
11
 
4
12
  # Flattens a hash or array, returning a hash where keys are a delimiter-separated string concatenation of all
5
13
  # nested keys. Returned keys are always strings. If a non-hash or array is provided, raises TypeError.
6
14
  # Please see rspec util_spec.rb for expected behavior.
7
15
  # Includes a known bug where defined delimiter will not be used for nesting levels past the first, this is kept
8
16
  # because some queries and dashboards already rely on the broken functionality.
9
- def self.flatten(obj, delimiter='_', flatten_arrays=true, fix_deep_flattening_delimiters=false)
17
+ def self.flatten(hash_obj, delimiter='_', flatten_arrays=true, fix_deep_flattening_delimiters=false, max_key_count=-1)
10
18
 
11
19
  # base case is input object is not enumerable, in which case simply return it
12
- if !obj.respond_to?(:each)
20
+ if !hash_obj.respond_to?(:each)
13
21
  raise TypeError.new('Input must be a hash or array')
14
22
  end
23
+ # case where we pass in a valid array, but don't want to flatten arrays
24
+ if !hash_obj.respond_to?(:has_key?) and !flatten_arrays
25
+ return hash_obj
26
+ end
15
27
 
28
+ stack = []
29
+ stack << hash_obj
30
+ key_stack = []
31
+ key_stack << ""
32
+ key_list = []
33
+ key_list_width = []
16
34
  result = Hash.new
17
- # require 'pry'
18
- # binding.pry
19
-
20
- if obj.respond_to?(:has_key?)
21
-
22
- # input object is a hash
23
- obj.each do |key, value|
24
- if (flatten_arrays and value.respond_to?(:each)) or value.respond_to?(:has_key?)
25
- flatten(value, fix_deep_flattening_delimiters ? delimiter : '_', flatten_arrays).each do |subkey, subvalue|
26
- result["#{key}#{delimiter}#{subkey}"] = subvalue
27
- end
28
- else
29
- result["#{key}"] = value
35
+ test_key = 0
36
+ #Debugging
37
+ #require 'pry'
38
+ #binding.pry
39
+
40
+ until stack.empty?
41
+ obj = stack.pop
42
+ key_list << key_stack.pop
43
+
44
+ # Case when object is a hash
45
+ if obj.respond_to?(:has_key?) and obj.keys.count > 0
46
+ key_list_width << obj.keys.count
47
+ obj.each do |key, value|
48
+ key_stack << key
49
+ stack << value
30
50
  end
31
- end
32
51
 
33
- elsif flatten_arrays
52
+ # Case when object is an array we intend to flatten
53
+ elsif flatten_arrays and obj.respond_to?(:each) and obj.count > 0
54
+ key_list_width << obj.count
55
+ obj.each_with_index do |value, index|
56
+ key_stack << index
57
+ stack << value
58
+ end
34
59
 
35
- # input object is an array or set
36
- obj.each_with_index do |value, index|
37
- if value.respond_to?(:each)
38
- flatten(value, fix_deep_flattening_delimiters ? delimiter : '_', flatten_arrays).each do |subkey, subvalue|
39
- result["#{index}#{delimiter}#{subkey}"] = subvalue
60
+ else
61
+ result_key = ""
62
+ delim = delimiter
63
+ key_list.each_with_index do |key, index|
64
+ # We have a blank key at the start of the key list to avoid issues with calling pop, so we ignore delimiter
65
+ # for the first two keys
66
+ if index > 1
67
+ result_key += "#{delim}#{key}"
68
+ if not fix_deep_flattening_delimiters
69
+ delim = "_"
70
+ end
71
+ else
72
+ result_key += "#{key}"
40
73
  end
41
- else
42
- result["#{index}"] = value
43
74
  end
44
- end
75
+ result[result_key] = obj
45
76
 
46
- else
77
+ if max_key_count > -1 and result.keys.count > max_key_count
78
+ raise MaxKeyCountError.new(
79
+ "Resulting flattened object will contain more keys than the configured flattening_max_key_count of #{max_key_count}",
80
+ result.keys[0..6]
81
+ )
82
+ end
47
83
 
48
- result = obj
84
+ throw_away = key_list.pop
85
+ until key_list_width.empty? or key_list_width[-1] > 1
86
+ throw_away = key_list_width.pop
87
+ throw_away = key_list.pop
88
+ end
89
+ if not key_list_width.empty?
90
+ key_list_width[-1] -= 1
91
+ end
49
92
 
93
+ end
50
94
  end
51
95
 
52
96
  return result
@@ -1,2 +1,2 @@
1
1
  # encoding: utf-8
2
- PLUGIN_VERSION = "v0.1.19.beta"
2
+ PLUGIN_VERSION = "v0.1.23.beta"
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-output-scalyr'
3
- s.version = '0.1.19.beta'
3
+ s.version = '0.1.23.beta'
4
4
  s.licenses = ['Apache-2.0']
5
5
  s.summary = "Scalyr output plugin for Logstash"
6
6
  s.description = "Sends log data collected by Logstash to Scalyr (https://www.scalyr.com)"
@@ -7,6 +7,12 @@ require "json"
7
7
  require 'webmock/rspec'
8
8
  WebMock.allow_net_connect!
9
9
 
10
+ RSpec.configure do |rspec|
11
+ rspec.expect_with :rspec do |c|
12
+ c.max_formatted_output_length = nil
13
+ end
14
+ end
15
+
10
16
  describe LogStash::Outputs::Scalyr do
11
17
  let(:sample_events) {
12
18
  events = []
@@ -58,7 +64,7 @@ describe LogStash::Outputs::Scalyr do
58
64
  {
59
65
  :error_class=>"Manticore::UnknownException",
60
66
  :batch_num=>1,
61
- :message=>"Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty",
67
+ :message=>"java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty",
62
68
  :payload_size=>781,
63
69
  :record_count=>3,
64
70
  :total_batches=>1,
@@ -84,7 +90,7 @@ describe LogStash::Outputs::Scalyr do
84
90
  {
85
91
  :error_class=>"Manticore::UnknownException",
86
92
  :batch_num=>1,
87
- :message=>"Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty",
93
+ :message=>"java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty",
88
94
  :payload_size=>781,
89
95
  :record_count=>3,
90
96
  :total_batches=>1,