logstash-output-scalyr 0.1.26.beta → 0.2.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -1
- data/README.md +109 -2
- data/lib/logstash/outputs/scalyr.rb +83 -23
- data/lib/scalyr/common/client.rb +2 -1
- data/lib/scalyr/common/util.rb +28 -1
- data/lib/scalyr/constants.rb +4 -1
- data/logstash-output-scalyr.gemspec +1 -1
- data/spec/benchmarks/bignum_fixing.rb +2 -5
- data/spec/benchmarks/flattening_and_serialization.rb +1 -1
- data/spec/benchmarks/json_serialization.rb +1 -1
- data/spec/benchmarks/set_session_level_serverhost_on_events.rb +109 -0
- data/spec/logstash/outputs/scalyr_integration_spec.rb +7 -7
- data/spec/logstash/outputs/scalyr_spec.rb +322 -17
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d2f63d5c51030c7bbb033edc0d7f8b8d3affff48f94f0bb2134fdfb75af36a76
|
4
|
+
data.tar.gz: 5787605f828a4a4f7d992003ed8a27e1f67439c49fab37d91c5077aa08d50428
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba560b44dd9ad73f56b2f105007a37bedd5b7821f7776c8d58c44ec7bb0fa544e80bd287756f8bb6ca76d53eedd3a1f36131cc60f2e7cf26ef9937af21c0a5a9
|
7
|
+
data.tar.gz: 4c8e3d4528ab613bd506e8b87e014ddfbd9725a088171396d483826348e8e7467ca75b1164dadb082b3d0732b37bfe4d4d1985b86cfb4ca389f592294055d2a3
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,24 @@
|
|
1
1
|
# Beta
|
2
2
|
|
3
|
+
## 0.2.0.beta
|
4
|
+
|
5
|
+
- Fix a bug and correctly handle ``serverHost`` event level attribute. Now if an event contains
|
6
|
+
``serverHost`` attribute, this attribute will be correctly set on the event level and available for
|
7
|
+
"Sources" filtering in the UI.
|
8
|
+
- Plugin doesn't set ``serverHost`` attribute with a fixed value of ``Logstash`` on each event
|
9
|
+
level anymore. If you still want this behavior, you can achieve that with logstash mutate filter.
|
10
|
+
- Session level ``serverHost`` value now defaults to logstash aggregator node hostname
|
11
|
+
(``use_hostname_for_serverhost`` config option now defaults to true).
|
12
|
+
- ``host`` attribute is not removed by default from all the events. By default, logstash adds
|
13
|
+
``host`` attribute which contains logstash aggregator host to each event. This is now redundant
|
14
|
+
and unncessary with the fixed and improved serverHost behavior (host and serverHost would contain
|
15
|
+
the same value by default). If you want to change this behavior and and still include ``host``
|
16
|
+
attribute on each event you can do that by setting ``remove_host_attribute_from_events`` config
|
17
|
+
option to false.
|
18
|
+
|
3
19
|
## 0.1.26.beta
|
4
20
|
- Add support for new ``json_library`` config option. Valid values are ``stdlib`` (default) are ``jrjackson``. The later may offer 2-4x faster JSON serialization.
|
5
21
|
|
6
|
-
|
7
22
|
## 0.1.23.beta
|
8
23
|
- Add testing support for disabling estimation of serialized event size for each event in the batch.
|
9
24
|
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ You can view documentation for this plugin [on the Scalyr website](https://app.s
|
|
9
9
|
# Quick start
|
10
10
|
|
11
11
|
1. Build the gem, run `gem build logstash-output-scalyr.gemspec`
|
12
|
-
2. Install the gem into a Logstash installation, run `/usr/share/logstash/bin/logstash-plugin install logstash-output-scalyr-0.
|
12
|
+
2. Install the gem into a Logstash installation, run `/usr/share/logstash/bin/logstash-plugin install logstash-output-scalyr-0.2.0.beta.gem` or follow the latest official instructions on working with plugins from Logstash.
|
13
13
|
3. Configure the output plugin (e.g. add it to a pipeline .conf)
|
14
14
|
4. Restart Logstash
|
15
15
|
|
@@ -39,6 +39,51 @@ output {
|
|
39
39
|
|
40
40
|
In the above example, the Logstash pipeline defines a file input that reads from `/var/log/messages`. Log events from this source have the `host` and `path` fields. The pipeline then outputs to the scalyr plugin, which in this example is configured to remap `host`->`serverHost` and `path`->`logfile`, thus facilitating filtering in the Scalyr UI.
|
41
41
|
|
42
|
+
## Notes on serverHost attribute handling
|
43
|
+
|
44
|
+
> Some of this functionality has been fixed and changed in the v0.2.0beta release. In previous
|
45
|
+
versions, plugin added ``serverHost`` attribute with a value of ``Logstash`` to each event and
|
46
|
+
this attribute was not handled correctly - it was treated as a regular event level attribute
|
47
|
+
and not a special attribute which can be used for Source functionality and filtering.
|
48
|
+
|
49
|
+
By default this plugin will set ``serverHost`` for all the events in a batch to match hostname of
|
50
|
+
the logstash node where the output plugin is running.
|
51
|
+
|
52
|
+
You can change that either by setting ``serverHost`` attribute in the ``server_attributes`` config
|
53
|
+
option hash or by setting ``serverHost`` attribute on the event level via logstash record attribute.
|
54
|
+
|
55
|
+
In both scenarios, you will be able to utilize this value for "Sources" functionality and filterin
|
56
|
+
in the Scalyr UI.
|
57
|
+
|
58
|
+
For example:
|
59
|
+
|
60
|
+
1. Define static value for all the events handled by specific plugin instance
|
61
|
+
|
62
|
+
```
|
63
|
+
output {
|
64
|
+
scalyr {
|
65
|
+
api_write_token => 'SCALYR_API_KEY'
|
66
|
+
server_attributes => {'serverHost' => 'my-host-1'}
|
67
|
+
}
|
68
|
+
}
|
69
|
+
```
|
70
|
+
|
71
|
+
2. Define static value on the event level which is set via logstash filter
|
72
|
+
|
73
|
+
```
|
74
|
+
mutate {
|
75
|
+
add_field => { "serverHost" => "my hostname" }
|
76
|
+
}
|
77
|
+
```
|
78
|
+
|
79
|
+
3. Define dynamic value on the event level which is set via logstash filter
|
80
|
+
|
81
|
+
```
|
82
|
+
mutate {
|
83
|
+
add_field => { "serverHost" => "%{[host][name]}" }
|
84
|
+
}
|
85
|
+
```
|
86
|
+
|
42
87
|
## Options
|
43
88
|
|
44
89
|
- The Scalyr API write token, these are available at https://www.scalyr.com/keys. This is the only compulsory configuration field required for proper upload
|
@@ -71,7 +116,7 @@ In the above example, the Logstash pipeline defines a file input that reads from
|
|
71
116
|
- Related to the server_attributes dictionary above, if you do not define the 'serverHost' key in server_attributes,
|
72
117
|
the plugin will automatically set it, using the aggregator hostname as value, if this value is true.
|
73
118
|
|
74
|
-
`config :use_hostname_for_serverhost, :validate => :boolean, :default =>
|
119
|
+
`config :use_hostname_for_serverhost, :validate => :boolean, :default => true`
|
75
120
|
|
76
121
|
---
|
77
122
|
|
@@ -394,3 +439,65 @@ bundle exec rake publish_gem
|
|
394
439
|
|
395
440
|
`RUBY_USER` and `RUBY_PASSWORD` should be replaced with the username and password to the RubyGems.org account you wish to release to,
|
396
441
|
these credentials should be found in Keeper.
|
442
|
+
|
443
|
+
# Testing Plugin Changes
|
444
|
+
|
445
|
+
This section describes how to test the plugin and changes using docker compose setup from
|
446
|
+
lostash-config-tester repo available at https://github.com/Kami/logstash-config-tester.
|
447
|
+
|
448
|
+
This repo has been forked and already contains some changes which make testing the plugin
|
449
|
+
easier.
|
450
|
+
|
451
|
+
The logstash configuration in that repo is set up to receive records encoded as JSON via
|
452
|
+
standard input, decode the JSON into the event object and print it to stdout + send it
|
453
|
+
to the Scalyr output.
|
454
|
+
|
455
|
+
```bash
|
456
|
+
# 0. Clone the tester repo
|
457
|
+
git clone https://github.com/Kami/logstash-config-tester ~/
|
458
|
+
|
459
|
+
# 1. Build the plugin
|
460
|
+
gem build logstash-output-scalyr.gemspec
|
461
|
+
|
462
|
+
# 2. Copy it to the config test repo
|
463
|
+
cp logstash-output-scalyr-0.2.0.beta.gem ~/logstash-config-test/logstash-output-scalyr.gem
|
464
|
+
|
465
|
+
# 3. Build docker image with the latest dev version of the plugin (may take a while)
|
466
|
+
docker-compose build
|
467
|
+
|
468
|
+
# 4. Configure API key in docker-compose.yml and make any changes to plugin config in
|
469
|
+
# pipeline/scalyr_output.conf.j2, if necessary
|
470
|
+
vim docker-compose.yml
|
471
|
+
|
472
|
+
vim pipeline/scalyr_output.conf.j2
|
473
|
+
|
474
|
+
# 4. Run logstash with the stdin input and stdout + scalyr output
|
475
|
+
docker-compose run logstash
|
476
|
+
```
|
477
|
+
|
478
|
+
A couple of things to keep in mind:
|
479
|
+
|
480
|
+
1. Logstash log level is set to debug which is quite verbose, but it makes troubleshooting and
|
481
|
+
testing easier.
|
482
|
+
2. Plugin accepts records (events) as JSON via standard input. This means to inject the mock
|
483
|
+
event you can simply copy the JSON event representation string to stdin and press enter. If you
|
484
|
+
want to submit multiples events to be handled as a single batch, paste each event one at a time
|
485
|
+
and press enter at the end. Logstash pipeline has been configured to wait up to 5 seconds before
|
486
|
+
handling the batch which should give you enough time to test batches with multiple events (this
|
487
|
+
setting can be adjusted in ``config/logstash.yml`` - ``pipeline.batch.delay``, if needed)
|
488
|
+
|
489
|
+
Example values you can enter into stdin:
|
490
|
+
|
491
|
+
1. Single event batch
|
492
|
+
|
493
|
+
```javascript
|
494
|
+
{"foo": "bar", "message": "test logstash"}
|
495
|
+
```
|
496
|
+
|
497
|
+
2. Batch with 3 events
|
498
|
+
|
499
|
+
```javascript
|
500
|
+
{"serverHost": "host-1", "bar": "baz", "message": "test logstash 1"}
|
501
|
+
{"serverHost": "host-2", "bar": "baz", "message": "test logstash 2"}
|
502
|
+
{"bar": "baz", "message": "test logstash 3"}
|
503
|
+
```
|
@@ -43,7 +43,7 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
43
43
|
|
44
44
|
# Related to the server_attributes dictionary above, if you do not define the 'serverHost' key in server_attributes,
|
45
45
|
# the plugin will automatically set it, using the aggregator hostname as value, if this value is true.
|
46
|
-
config :use_hostname_for_serverhost, :validate => :boolean, :default =>
|
46
|
+
config :use_hostname_for_serverhost, :validate => :boolean, :default => true
|
47
47
|
|
48
48
|
# Field that represents the origin of the log event.
|
49
49
|
# (Warning: events with an existing 'serverHost' field, it will be overwritten)
|
@@ -66,6 +66,23 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
66
66
|
# value with have fields moved.
|
67
67
|
config :log_constants, :validate => :array, :default => nil
|
68
68
|
|
69
|
+
# When this option is true and session level server host is defined (either via
|
70
|
+
# server_attributes config option or via node hostname) and some events in a batch contain
|
71
|
+
# "serverHost" attributes, other nodes in a batch which don't contain it will have serverHost
|
72
|
+
# set to the session level value.
|
73
|
+
# This is needed because session level attribute has priority over event level which means
|
74
|
+
# that in case we specify serverHost on some events, other events won't have any value set
|
75
|
+
# for serverHost.
|
76
|
+
# Since this option adds some overhead and requires additional processing time, it's
|
77
|
+
# disabled by default.
|
78
|
+
config :set_session_level_serverhost_on_events, validate: :boolean, default: false
|
79
|
+
|
80
|
+
# By default, logstash will add "host" attribute which includes logstash aggregator server
|
81
|
+
# host to each event. This is not really needed and desired anymore with the fixed and improved
|
82
|
+
# serverHost attribute handling (serverHost now contains logstash aggregator hostname by
|
83
|
+
# default).
|
84
|
+
config :remove_host_attribute_from_events, validate: :boolean, default: true
|
85
|
+
|
69
86
|
# If true, nested values will be flattened (which changes keys to delimiter-separated concatenation of all
|
70
87
|
# nested keys).
|
71
88
|
config :flatten_nested_values, :validate => :boolean, :default => false
|
@@ -241,12 +258,13 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
241
258
|
@server_attributes = new_attributes
|
242
259
|
end
|
243
260
|
|
244
|
-
# See if we should use the hostname as the server_attributes.serverHost
|
245
|
-
|
246
|
-
|
261
|
+
# See if we should use the hostname as the server_attributes.serverHost (aka if fixed serverHost is not
|
262
|
+
# defined as part of server_attributes config option)
|
263
|
+
if @server_attributes.nil?
|
247
264
|
@server_attributes = {}
|
248
|
-
|
265
|
+
end
|
249
266
|
|
267
|
+
if @use_hostname_for_serverhost
|
250
268
|
# only set serverHost if it doesn't currently exist in server_attributes
|
251
269
|
# Note: Use strings rather than symbols for the key, because keys coming
|
252
270
|
# from the config file will be strings
|
@@ -258,6 +276,15 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
258
276
|
# Add monitor server attribute to identify this as coming from a plugin
|
259
277
|
@server_attributes['monitor'] = 'pluginLogstash'
|
260
278
|
|
279
|
+
# We create a fixed copy without host here so we can reference this later if needed to avoid
|
280
|
+
# some of the copy + manipulate overhead per batch
|
281
|
+
@server_attributes_without_serverhost = @server_attributes.clone
|
282
|
+
if @server_attributes_without_serverhost.key? "serverHost"
|
283
|
+
@server_attributes_without_serverhost.delete "serverHost"
|
284
|
+
end
|
285
|
+
|
286
|
+
@session_server_host = @server_attributes["serverHost"]
|
287
|
+
|
261
288
|
@scalyr_server << '/' unless @scalyr_server.end_with?('/')
|
262
289
|
|
263
290
|
@add_events_uri = URI(@scalyr_server) + "addEvents"
|
@@ -290,7 +317,8 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
290
317
|
@http_connect_timeout, @http_socket_timeout, @http_request_timeout, @http_pool_max, @http_pool_max_per_route
|
291
318
|
)
|
292
319
|
|
293
|
-
@logger.info(sprintf("Started Scalyr output plugin
|
320
|
+
@logger.info(sprintf("Started Scalyr LogStash output plugin %s (compression_type=%s,compression_level=%s,json_library=%s)." %
|
321
|
+
[PLUGIN_VERSION, @compression_type, @compression_type, @json_library]), :class => self.class.name)
|
294
322
|
|
295
323
|
# Finally, send a status line to Scalyr
|
296
324
|
# We use a special separate short lived client session for sending the initial client status.
|
@@ -505,7 +533,7 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
505
533
|
@dlq_writer.write(l_event, "#{exc_data[:message]}")
|
506
534
|
}
|
507
535
|
else
|
508
|
-
@logger.warn("
|
536
|
+
@logger.warn("Dead letter queue not configured, dropping #{multi_event_request[:logstash_events].length} events after #{exc_retries} tries.", :sample_events => sample_events)
|
509
537
|
end
|
510
538
|
end
|
511
539
|
|
@@ -549,6 +577,8 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
549
577
|
logs_ids = Hash.new
|
550
578
|
next_log_id = 1
|
551
579
|
|
580
|
+
batch_has_event_level_server_host = false
|
581
|
+
|
552
582
|
logstash_events.each {|l_event|
|
553
583
|
|
554
584
|
record = l_event.to_hash
|
@@ -604,6 +634,11 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
604
634
|
# Rename user-specified logfile field -> 'logfile'
|
605
635
|
rename.call(@logfile_field, 'logfile')
|
606
636
|
|
637
|
+
# Remove "host" attribute
|
638
|
+
if @remove_host_attribute_from_events and record.key? "host"
|
639
|
+
record.delete("host")
|
640
|
+
end
|
641
|
+
|
607
642
|
# Set a default parser is none is present in the event
|
608
643
|
if record['parser'].to_s.empty?
|
609
644
|
record['parser'] = "logstashParser"
|
@@ -614,26 +649,31 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
614
649
|
record['logfile'] = "/logstash/#{serverHost}"
|
615
650
|
end
|
616
651
|
|
617
|
-
#
|
618
|
-
|
619
|
-
|
652
|
+
# Rename serverHost (if exists) to __origServerHost so sources filtering works correctly
|
653
|
+
# It's important that this happens at the very end of the event processing in this function.
|
654
|
+
record_has_server_host_attribute = record.key? 'serverHost'
|
655
|
+
batch_has_event_level_server_host |= record_has_server_host_attribute
|
656
|
+
|
657
|
+
if record_has_server_host_attribute
|
658
|
+
record[EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME] = record['serverHost']
|
659
|
+
record.delete('serverHost')
|
620
660
|
end
|
621
661
|
|
662
|
+
# To reduce duplication of common event-level attributes, we "fold" them into top-level "logs" attribute
|
663
|
+
# and reference log entry inside the event
|
622
664
|
log_identifier = nil
|
623
665
|
add_log = false
|
624
666
|
if serverHost
|
625
667
|
log_identifier = serverHost + record['logfile']
|
626
668
|
end
|
669
|
+
|
627
670
|
if log_identifier and not logs.key? log_identifier
|
628
671
|
add_log = true
|
629
672
|
logs[log_identifier] = {
|
630
673
|
'id' => next_log_id,
|
631
674
|
'attrs' => Hash.new
|
632
675
|
}
|
633
|
-
|
634
|
-
logs[log_identifier]['attrs']['serverHost'] = record['serverHost']
|
635
|
-
record.delete('serverHost')
|
636
|
-
end
|
676
|
+
|
637
677
|
if not record['logfile'].to_s.empty?
|
638
678
|
logs[log_identifier]['attrs']['logfile'] = record['logfile']
|
639
679
|
record.delete('logfile')
|
@@ -646,10 +686,21 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
646
686
|
end
|
647
687
|
}
|
648
688
|
end
|
689
|
+
|
649
690
|
logs_ids[log_identifier] = next_log_id
|
650
691
|
next_log_id += 1
|
651
692
|
end
|
652
693
|
|
694
|
+
# If we already contain "logs" entry for this record, we remove duplicated serverHost from
|
695
|
+
# the event attributes since it's already part of the log level attributes which are
|
696
|
+
# referenced by the event.
|
697
|
+
if log_identifier and logs.key? log_identifier
|
698
|
+
if not record[EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME].to_s.empty?
|
699
|
+
logs[log_identifier]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME] = record[EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]
|
700
|
+
record.delete(EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME)
|
701
|
+
end
|
702
|
+
end
|
703
|
+
|
653
704
|
# Delete unwanted fields from record
|
654
705
|
record.delete('@version')
|
655
706
|
record.delete('@timestamp')
|
@@ -695,7 +746,7 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
695
746
|
:attrs => record
|
696
747
|
}
|
697
748
|
|
698
|
-
# optionally set thread
|
749
|
+
# optionally set thread and referenced log file
|
699
750
|
if serverHost
|
700
751
|
scalyr_event[:thread] = thread_id.to_s
|
701
752
|
scalyr_event[:log] = logs_ids[log_identifier]
|
@@ -756,7 +807,8 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
756
807
|
append_event = false
|
757
808
|
end
|
758
809
|
|
759
|
-
|
810
|
+
Scalyr::Common::Util.set_session_level_serverhost_on_events(@session_server_host, scalyr_events, logs, batch_has_event_level_server_host)
|
811
|
+
multi_event_request = self.create_multi_event_request(scalyr_events, l_events, current_threads, logs, batch_has_event_level_server_host)
|
760
812
|
multi_event_request_array << multi_event_request
|
761
813
|
|
762
814
|
total_bytes = 0
|
@@ -765,6 +817,7 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
765
817
|
logs_ids = Hash.new
|
766
818
|
scalyr_events = Array.new
|
767
819
|
l_events = Array.new
|
820
|
+
batch_has_event_level_server_host = false
|
768
821
|
end
|
769
822
|
else
|
770
823
|
# If size estimation is disabled we simply append the event and handle splitting later on (if needed)
|
@@ -784,14 +837,14 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
784
837
|
|
785
838
|
# create a final request with any left over events (and make sure there is at least one event)
|
786
839
|
if scalyr_events.size >= 1
|
787
|
-
|
840
|
+
Scalyr::Common::Util.set_session_level_serverhost_on_events(@session_server_host, scalyr_events, logs, batch_has_event_level_server_host)
|
841
|
+
multi_event_request = self.create_multi_event_request(scalyr_events, l_events, current_threads, logs, batch_has_event_level_server_host)
|
788
842
|
multi_event_request_array << multi_event_request
|
789
843
|
end
|
790
844
|
|
791
845
|
multi_event_request_array
|
792
846
|
end
|
793
847
|
|
794
|
-
|
795
848
|
# Helper method that adds a client_timestamp to a batch addEvents request body
|
796
849
|
def add_client_timestamp_to_body(body)
|
797
850
|
current_time_millis = DateTime.now.strftime('%Q').to_i
|
@@ -804,7 +857,7 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
804
857
|
# A request comprises multiple Scalyr Events. This function creates a request hash for
|
805
858
|
# final upload to Scalyr (from an array of events, and an optional hash of current threads)
|
806
859
|
# Note: The request body field will be json-encoded.
|
807
|
-
def create_multi_event_request(scalyr_events, logstash_events, current_threads, current_logs)
|
860
|
+
def create_multi_event_request(scalyr_events, logstash_events, current_threads, current_logs, batch_has_event_level_server_host = false)
|
808
861
|
|
809
862
|
body = {
|
810
863
|
:session => @session_id + Thread.current.object_id.to_s,
|
@@ -833,7 +886,13 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
833
886
|
end
|
834
887
|
|
835
888
|
# add serverAttributes
|
836
|
-
|
889
|
+
# If serverHost is defined on any of the events, we don't send it via sessionInfo since
|
890
|
+
# sesionInfo has the higest priority and would always overwritte the event level one
|
891
|
+
if batch_has_event_level_server_host
|
892
|
+
body[:sessionInfo] = @server_attributes_without_serverhost if @server_attributes_without_serverhost
|
893
|
+
else
|
894
|
+
body[:sessionInfo] = @server_attributes if @server_attributes
|
895
|
+
end
|
837
896
|
|
838
897
|
# We time serialization to get some insight on how long it takes to serialize the request body
|
839
898
|
start_time = Time.now.to_f
|
@@ -926,8 +985,9 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
926
985
|
}
|
927
986
|
@send_stats.synchronize do
|
928
987
|
if !@last_status_transmit_time
|
929
|
-
status_event[:attrs]['message'] = sprintf("Started Scalyr LogStash output plugin
|
930
|
-
|
988
|
+
status_event[:attrs]['message'] = sprintf("Started Scalyr LogStash output plugin %s (compression_type=%s,compression_level=%s,json_library=%s)." %
|
989
|
+
[PLUGIN_VERSION, @compression_type, @compression_type, @json_library])
|
990
|
+
status_event[:attrs][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME] = @node_hostname
|
931
991
|
else
|
932
992
|
cur_time = Time.now()
|
933
993
|
return if (cur_time.to_i - @last_status_transmit_time.to_i) < @status_report_interval
|
@@ -949,7 +1009,7 @@ class LogStash::Outputs::Scalyr < LogStash::Outputs::Base
|
|
949
1009
|
cnt += 1
|
950
1010
|
end
|
951
1011
|
status_event[:attrs]['message'] = msg
|
952
|
-
status_event[:attrs][
|
1012
|
+
status_event[:attrs][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME] = @node_hostname
|
953
1013
|
status_event[:attrs]['parser'] = @status_parser
|
954
1014
|
end
|
955
1015
|
multi_event_request = create_multi_event_request([status_event], nil, nil, nil)
|
data/lib/scalyr/common/client.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "scalyr/constants"
|
2
|
+
require "logstash-core"
|
2
3
|
|
3
4
|
module Scalyr; module Common; module Client
|
4
5
|
|
@@ -298,7 +299,7 @@ class ClientSession
|
|
298
299
|
version = sprintf('output-logstash-scalyr %s' % [PLUGIN_VERSION])
|
299
300
|
post_headers = {
|
300
301
|
'Content-Type': 'application/json',
|
301
|
-
'User-Agent': version + ';' + RUBY_VERSION + ';' + RUBY_PLATFORM
|
302
|
+
'User-Agent': version + ';' + RUBY_VERSION + ';' + RUBY_PLATFORM + ';' + LOGSTASH_VERSION
|
302
303
|
}
|
303
304
|
|
304
305
|
post_body = nil
|
data/lib/scalyr/common/util.rb
CHANGED
@@ -124,5 +124,32 @@ def self.convert_bignums(obj)
|
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
127
|
-
end; end; end;
|
128
127
|
|
128
|
+
# Function which sets special serverHost attribute on the events without this special attribute
|
129
|
+
# to session level serverHost value
|
130
|
+
# NOTE: This method mutates scalyr_events in place.
|
131
|
+
def self.set_session_level_serverhost_on_events(session_server_host, scalyr_events, logs, batch_has_event_level_server_host = false)
|
132
|
+
# Maps log id (number) to logfile attributes for more efficient lookups later on
|
133
|
+
logs_ids_to_attrs = Hash.new
|
134
|
+
|
135
|
+
logs.each {|_, log|
|
136
|
+
logs_ids_to_attrs[log["id"]] = log["attrs"]
|
137
|
+
}
|
138
|
+
|
139
|
+
if batch_has_event_level_server_host
|
140
|
+
scalyr_events.each {|s_event|
|
141
|
+
log_id = s_event[:log]
|
142
|
+
logfile_attrs = logs_ids_to_attrs[log_id]
|
143
|
+
|
144
|
+
if logfile_attrs.nil?
|
145
|
+
logfile_attrs = Hash.new
|
146
|
+
end
|
147
|
+
|
148
|
+
if s_event[:attrs][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME].nil? and logfile_attrs[EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME].nil?
|
149
|
+
s_event[:attrs][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME] = session_server_host
|
150
|
+
end
|
151
|
+
}
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end; end; end;
|
data/lib/scalyr/constants.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'logstash-output-scalyr'
|
3
|
-
s.version = '0.
|
3
|
+
s.version = '0.2.0.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)"
|
@@ -2,15 +2,12 @@ require 'benchmark'
|
|
2
2
|
require 'quantile'
|
3
3
|
|
4
4
|
require_relative '../../lib/scalyr/common/util'
|
5
|
+
require_relative './util'
|
5
6
|
|
6
7
|
# Micro benchmark which measures how long it takes to find all the Bignums in a record and convert them to strings
|
7
8
|
|
8
9
|
ITERATIONS = 500
|
9
10
|
|
10
|
-
def rand_str(len)
|
11
|
-
return (0...len).map { (65 + rand(26)).chr }.join
|
12
|
-
end
|
13
|
-
|
14
11
|
def rand_bignum()
|
15
12
|
return 200004000020304050300 + rand(999999)
|
16
13
|
end
|
@@ -43,7 +40,7 @@ def run_benchmark_and_print_results(data, run_benchmark_func)
|
|
43
40
|
|
44
41
|
result = []
|
45
42
|
ITERATIONS.times do |i|
|
46
|
-
result << Benchmark.measure { run_benchmark_func.(data[
|
43
|
+
result << Benchmark.measure { run_benchmark_func.(data[i]) }
|
47
44
|
end
|
48
45
|
|
49
46
|
sum = result.inject(nil) { |sum, t| sum.nil? ? sum = t : sum += t }
|
@@ -17,7 +17,7 @@ def run_benchmark_and_print_results(data, run_benchmark_func)
|
|
17
17
|
|
18
18
|
result = []
|
19
19
|
ITERATIONS.times do |i|
|
20
|
-
result << Benchmark.measure { run_benchmark_func.(data[
|
20
|
+
result << Benchmark.measure { run_benchmark_func.(data[i]) }
|
21
21
|
end
|
22
22
|
|
23
23
|
sum = result.inject(nil) { |sum, t| sum.nil? ? sum = t : sum += t }
|
@@ -31,7 +31,7 @@ def run_benchmark_and_print_results(data, run_benchmark_func)
|
|
31
31
|
|
32
32
|
result = []
|
33
33
|
ITERATIONS.times do |i|
|
34
|
-
result << Benchmark.measure { run_benchmark_func.(data[
|
34
|
+
result << Benchmark.measure { run_benchmark_func.(data[i]) }
|
35
35
|
end
|
36
36
|
|
37
37
|
sum = result.inject(nil) { |sum, t| sum.nil? ? sum = t : sum += t }
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require 'quantile'
|
3
|
+
|
4
|
+
require_relative '../../lib/scalyr/constants'
|
5
|
+
require_relative '../../lib/scalyr/common/util'
|
6
|
+
require_relative './util'
|
7
|
+
|
8
|
+
# Micro benchmark which measures how long "set_session_level_serverhost_on_events" takes
|
9
|
+
|
10
|
+
ITERATIONS = 100
|
11
|
+
|
12
|
+
def run_benchmark_and_print_results(data, run_benchmark_func)
|
13
|
+
puts ""
|
14
|
+
puts "Using %s total events in a batch" % [data[0].size]
|
15
|
+
puts ""
|
16
|
+
|
17
|
+
result = []
|
18
|
+
ITERATIONS.times do |i|
|
19
|
+
result << Benchmark.measure { run_benchmark_func.(data[i]) }
|
20
|
+
end
|
21
|
+
|
22
|
+
sum = result.inject(nil) { |sum, t| sum.nil? ? sum = t : sum += t }
|
23
|
+
avg = sum / result.size
|
24
|
+
|
25
|
+
Benchmark.bm(7, "sum:", "avg:") do |b|
|
26
|
+
[sum, avg]
|
27
|
+
end
|
28
|
+
puts ""
|
29
|
+
end
|
30
|
+
|
31
|
+
# Generate random event with only single event having special server host attribute set which
|
32
|
+
# represents a worst case scenario since we need to backfill rest of the events.
|
33
|
+
def generate_events(count)
|
34
|
+
result = []
|
35
|
+
|
36
|
+
ITERATIONS.times do |iteration|
|
37
|
+
events = []
|
38
|
+
|
39
|
+
count.times do |index|
|
40
|
+
event = generate_hash([2])
|
41
|
+
event[:attrs] = Hash.new
|
42
|
+
event[:log] = 1
|
43
|
+
|
44
|
+
if index == count - 1
|
45
|
+
event[:attrs][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME] = format("test-host-%s", index)
|
46
|
+
end
|
47
|
+
|
48
|
+
events << event
|
49
|
+
end
|
50
|
+
|
51
|
+
raise "Assertion failed" unless events.size == count
|
52
|
+
|
53
|
+
result << events
|
54
|
+
end
|
55
|
+
|
56
|
+
raise "Assertion failed" unless result.size == ITERATIONS
|
57
|
+
result
|
58
|
+
end
|
59
|
+
|
60
|
+
def run_func(events)
|
61
|
+
# NOTE: This function manipulates events in place
|
62
|
+
events.each_with_index do |event, index|
|
63
|
+
if index < events.size - 1
|
64
|
+
# Last event will have _origServerHost set, but others won't
|
65
|
+
raise "Assertion failed" unless event[:attrs][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME].nil?
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
Scalyr::Common::Util.set_session_level_serverhost_on_events("session-server-host-dummy", events, {}, true)
|
70
|
+
|
71
|
+
events.each do |event|
|
72
|
+
raise "Assertion failed" unless event[:attrs][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME].nil? == false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
puts "Using %s iterations" % [ITERATIONS]
|
78
|
+
puts ""
|
79
|
+
|
80
|
+
@value = Quantile::Estimator.new
|
81
|
+
|
82
|
+
puts "Util.set_session_level_serverhost_on_events()"
|
83
|
+
puts "==============================="
|
84
|
+
|
85
|
+
# 100 events in a batch
|
86
|
+
data = generate_events(100)
|
87
|
+
run_benchmark_and_print_results(data, method(:run_func))
|
88
|
+
|
89
|
+
|
90
|
+
# 500 events in a batch
|
91
|
+
data = generate_events(500)
|
92
|
+
run_benchmark_and_print_results(data, method(:run_func))
|
93
|
+
|
94
|
+
# 1000 events in a batch
|
95
|
+
data = generate_events(1000)
|
96
|
+
run_benchmark_and_print_results(data, method(:run_func))
|
97
|
+
|
98
|
+
# 2000 events in a batch
|
99
|
+
data = generate_events(2000)
|
100
|
+
run_benchmark_and_print_results(data, method(:run_func))
|
101
|
+
|
102
|
+
# 3000 events in a batch
|
103
|
+
data = generate_events(3000)
|
104
|
+
run_benchmark_and_print_results(data, method(:run_func))
|
105
|
+
|
106
|
+
# 5000 events in a batch
|
107
|
+
data = generate_events(5000)
|
108
|
+
puts data.size
|
109
|
+
run_benchmark_and_print_results(data, method(:run_func))
|
@@ -42,7 +42,7 @@ describe LogStash::Outputs::Scalyr do
|
|
42
42
|
:batch_num=>1,
|
43
43
|
:code=>401,
|
44
44
|
:message=>"error/client/badParam",
|
45
|
-
:payload_size=>
|
45
|
+
:payload_size=>737,
|
46
46
|
:record_count=>3,
|
47
47
|
:total_batches=>1,
|
48
48
|
:url=>"https://agent.scalyr.com/addEvents",
|
@@ -65,7 +65,7 @@ describe LogStash::Outputs::Scalyr do
|
|
65
65
|
:error_class=>"Manticore::UnknownException",
|
66
66
|
:batch_num=>1,
|
67
67
|
:message=>"java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty",
|
68
|
-
:payload_size=>
|
68
|
+
:payload_size=>737,
|
69
69
|
:record_count=>3,
|
70
70
|
:total_batches=>1,
|
71
71
|
:url=>"https://agent.scalyr.com/addEvents",
|
@@ -91,7 +91,7 @@ describe LogStash::Outputs::Scalyr do
|
|
91
91
|
:error_class=>"Manticore::UnknownException",
|
92
92
|
:batch_num=>1,
|
93
93
|
:message=>"java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty",
|
94
|
-
:payload_size=>
|
94
|
+
:payload_size=>737,
|
95
95
|
:record_count=>3,
|
96
96
|
:total_batches=>1,
|
97
97
|
:url=>"https://agent.scalyr.com/addEvents",
|
@@ -130,7 +130,7 @@ describe LogStash::Outputs::Scalyr do
|
|
130
130
|
:error_class=>"Manticore::UnknownException",
|
131
131
|
:batch_num=>1,
|
132
132
|
:message=>"Host name 'invalid.mitm.should.fail.test.agent.scalyr.com' does not match the certificate subject provided by the peer (CN=*.scalyr.com)",
|
133
|
-
:payload_size=>
|
133
|
+
:payload_size=>737,
|
134
134
|
:record_count=>3,
|
135
135
|
:total_batches=>1,
|
136
136
|
:url=>"https://invalid.mitm.should.fail.test.agent.scalyr.com/addEvents",
|
@@ -175,7 +175,7 @@ describe LogStash::Outputs::Scalyr do
|
|
175
175
|
:batch_num=>1,
|
176
176
|
:code=>503,
|
177
177
|
:message=>"Invalid JSON response from server",
|
178
|
-
:payload_size=>
|
178
|
+
:payload_size=>737,
|
179
179
|
:record_count=>3,
|
180
180
|
:total_batches=>1,
|
181
181
|
:url=>"https://agent.scalyr.com/addEvents",
|
@@ -203,7 +203,7 @@ describe LogStash::Outputs::Scalyr do
|
|
203
203
|
:batch_num=>1,
|
204
204
|
:code=>500,
|
205
205
|
:message=>"Invalid JSON response from server",
|
206
|
-
:payload_size=>
|
206
|
+
:payload_size=>737,
|
207
207
|
:record_count=>3,
|
208
208
|
:total_batches=>1,
|
209
209
|
:url=>"https://agent.scalyr.com/addEvents",
|
@@ -231,7 +231,7 @@ describe LogStash::Outputs::Scalyr do
|
|
231
231
|
:batch_num=>1,
|
232
232
|
:code=>500,
|
233
233
|
:message=>"Invalid JSON response from server",
|
234
|
-
:payload_size=>
|
234
|
+
:payload_size=>737,
|
235
235
|
:record_count=>3,
|
236
236
|
:total_batches=>1,
|
237
237
|
:url=>"https://agent.scalyr.com/addEvents",
|
@@ -6,6 +6,7 @@ require "logstash/event"
|
|
6
6
|
require "json"
|
7
7
|
require "quantile"
|
8
8
|
|
9
|
+
NODE_HOSTNAME = Socket.gethostname
|
9
10
|
|
10
11
|
class MockClientSession
|
11
12
|
DEFAULT_STATS = {
|
@@ -103,7 +104,7 @@ describe LogStash::Outputs::Scalyr do
|
|
103
104
|
plugin.instance_variable_set(:@client_session, mock_client_session)
|
104
105
|
plugin.instance_variable_set(:@session_id, "some_session_id")
|
105
106
|
status_event = plugin.send_status
|
106
|
-
expect(status_event[:attrs]["message"]).to eq("Started Scalyr LogStash output plugin
|
107
|
+
expect(status_event[:attrs]["message"]).to eq("Started Scalyr LogStash output plugin %s (compression_type=deflate,compression_level=deflate,json_library=stdlib)." % [PLUGIN_VERSION])
|
107
108
|
|
108
109
|
# 2. Second send
|
109
110
|
plugin.instance_variable_set(:@last_status_transmit_time, 100)
|
@@ -210,7 +211,7 @@ describe LogStash::Outputs::Scalyr do
|
|
210
211
|
body = JSON.parse(result[0][:body])
|
211
212
|
expect(body['events'].size).to eq(3)
|
212
213
|
logattrs2 = body['logs'][2]['attrs']
|
213
|
-
expect(logattrs2.fetch(
|
214
|
+
expect(logattrs2.fetch(EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME, nil)).to eq('my host 3')
|
214
215
|
expect(logattrs2.fetch('logfile', nil)).to eq('/logstash/my host 3')
|
215
216
|
expect(logattrs2.fetch('tags', nil)).to eq(['t1', 't2', 't3'])
|
216
217
|
end
|
@@ -240,7 +241,7 @@ describe LogStash::Outputs::Scalyr do
|
|
240
241
|
body = JSON.parse(result[0][:body])
|
241
242
|
expect(body['events'].size).to eq(3)
|
242
243
|
logattrs2 = body['logs'][2]['attrs']
|
243
|
-
expect(logattrs2.fetch(
|
244
|
+
expect(logattrs2.fetch(EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME, nil)).to eq('my host 3')
|
244
245
|
expect(logattrs2.fetch('logfile', nil)).to eq('/logstash/my host 3')
|
245
246
|
end
|
246
247
|
end
|
@@ -258,7 +259,7 @@ describe LogStash::Outputs::Scalyr do
|
|
258
259
|
body = JSON.parse(result[0][:body])
|
259
260
|
expect(body['events'].size).to eq(3)
|
260
261
|
logattrs2 = body['logs'][2]['attrs']
|
261
|
-
expect(logattrs2.fetch(
|
262
|
+
expect(logattrs2.fetch(EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME, nil)).to eq('my host 3')
|
262
263
|
expect(logattrs2.fetch('logfile', nil)).to eq('my file 3')
|
263
264
|
end
|
264
265
|
end
|
@@ -287,7 +288,6 @@ describe LogStash::Outputs::Scalyr do
|
|
287
288
|
'seq' => 3,
|
288
289
|
'source_file' => 'my file 3',
|
289
290
|
'source_host' => 'my host 3',
|
290
|
-
'serverHost' => 'Logstash',
|
291
291
|
"tag_prefix_t1" => "true",
|
292
292
|
"tag_prefix_t2" => "true",
|
293
293
|
"tag_prefix_t3" => "true",
|
@@ -321,7 +321,6 @@ describe LogStash::Outputs::Scalyr do
|
|
321
321
|
'seq' => 3,
|
322
322
|
'source_file' => 'my file 3',
|
323
323
|
'source_host' => 'my host 3',
|
324
|
-
'serverHost' => 'Logstash',
|
325
324
|
"tag_prefix_t1" => "true",
|
326
325
|
"tag_prefix_t2" => "true",
|
327
326
|
"tag_prefix_t3" => "true",
|
@@ -353,7 +352,6 @@ describe LogStash::Outputs::Scalyr do
|
|
353
352
|
'seq' => 3,
|
354
353
|
'source_file' => 'my file 3',
|
355
354
|
'source_host' => 'my host 3',
|
356
|
-
'serverHost' => 'Logstash',
|
357
355
|
"tag_prefix_t1" => "true",
|
358
356
|
"tag_prefix_t2" => "true",
|
359
357
|
"tag_prefix_t3" => "true",
|
@@ -385,7 +383,6 @@ describe LogStash::Outputs::Scalyr do
|
|
385
383
|
'seq' => 3,
|
386
384
|
'source_file' => 'my file 3',
|
387
385
|
'source_host' => 'my host 3',
|
388
|
-
'serverHost' => 'Logstash',
|
389
386
|
"tag_prefix_t1" => "true",
|
390
387
|
"tag_prefix_t2" => "true",
|
391
388
|
"tag_prefix_t3" => "true",
|
@@ -428,7 +425,6 @@ describe LogStash::Outputs::Scalyr do
|
|
428
425
|
'seq' => 3,
|
429
426
|
'source_file' => 'my file 3',
|
430
427
|
'source_host' => 'my host 3',
|
431
|
-
'serverHost' => 'Logstash',
|
432
428
|
"tag_prefix_t1" => "true",
|
433
429
|
"tag_prefix_t2" => "true",
|
434
430
|
"tag_prefix_t3" => "true",
|
@@ -468,7 +464,6 @@ describe LogStash::Outputs::Scalyr do
|
|
468
464
|
'seq' => 3,
|
469
465
|
'source_file' => 'my file 3',
|
470
466
|
'source_host' => 'my host 3',
|
471
|
-
'serverHost' => 'Logstash',
|
472
467
|
"tag_prefix_t1" => "true",
|
473
468
|
"tag_prefix_t2" => "true",
|
474
469
|
"tag_prefix_t3" => "true",
|
@@ -503,7 +498,6 @@ describe LogStash::Outputs::Scalyr do
|
|
503
498
|
'seq' => 3,
|
504
499
|
'source_file' => 'my file 3',
|
505
500
|
'source_host' => 'my host 3',
|
506
|
-
'serverHost' => 'Logstash',
|
507
501
|
"tag_prefix_t1" => "true",
|
508
502
|
"tag_prefix_t2" => "true",
|
509
503
|
"tag_prefix_t3" => "true",
|
@@ -528,7 +522,6 @@ describe LogStash::Outputs::Scalyr do
|
|
528
522
|
'seq' => 3,
|
529
523
|
'source_file' => 'my file 3',
|
530
524
|
'source_host' => 'my host 3',
|
531
|
-
'serverHost' => 'Logstash',
|
532
525
|
"tags" => ["t1", "t2", "t3"],
|
533
526
|
"parser" => "logstashParser",
|
534
527
|
})
|
@@ -554,19 +547,278 @@ describe LogStash::Outputs::Scalyr do
|
|
554
547
|
'seq' => 3,
|
555
548
|
'source_file' => 'my file 3',
|
556
549
|
'source_host' => 'my host 3',
|
557
|
-
'serverHost' => 'Logstash',
|
558
550
|
"tags" => ["t1", "t2", "t3"],
|
559
551
|
"parser" => "logstashParser",
|
560
552
|
})
|
561
553
|
expect(plugin.instance_variable_get(:@logger)).to have_received(:warn).with("Error while flattening record",
|
562
554
|
{
|
563
555
|
:error_message=>"Resulting flattened object will contain more keys than the configured flattening_max_key_count of 3",
|
564
|
-
:sample_keys=>["
|
556
|
+
:sample_keys=>["parser", "tags_2", "tags_1", "tags_0"]
|
565
557
|
}
|
566
558
|
).exactly(3).times
|
567
559
|
end
|
568
560
|
end
|
569
561
|
|
562
|
+
context "serverHost attribute handling" do
|
563
|
+
it "no serverHost defined in server_attributes, no serverHost defined on event level - should use node hostname as the default session level value" do
|
564
|
+
config = {
|
565
|
+
'api_write_token' => '1234',
|
566
|
+
}
|
567
|
+
plugin = LogStash::Outputs::Scalyr.new(config)
|
568
|
+
|
569
|
+
allow(plugin).to receive(:send_status).and_return(nil)
|
570
|
+
plugin.register
|
571
|
+
e = LogStash::Event.new
|
572
|
+
result = plugin.build_multi_event_request_array([e])
|
573
|
+
body = JSON.parse(result[0][:body])
|
574
|
+
expect(body['sessionInfo']['serverHost']).to eq(NODE_HOSTNAME)
|
575
|
+
|
576
|
+
expect(body['logs']).to eq([])
|
577
|
+
expect(body['events'].size).to eq(1)
|
578
|
+
expect(body['events'][0]['attrs']["serverHost"]).to eq(nil)
|
579
|
+
end
|
580
|
+
|
581
|
+
it "serverHost defined in server_attributes, nothing defined on event level - server_attributes value should be used" do
|
582
|
+
config = {
|
583
|
+
'api_write_token' => '1234',
|
584
|
+
'server_attributes' => {'serverHost' => 'fooHost'}
|
585
|
+
}
|
586
|
+
plugin = LogStash::Outputs::Scalyr.new(config)
|
587
|
+
|
588
|
+
allow(plugin).to receive(:send_status).and_return(nil)
|
589
|
+
plugin.register
|
590
|
+
e = LogStash::Event.new
|
591
|
+
result = plugin.build_multi_event_request_array([e])
|
592
|
+
body = JSON.parse(result[0][:body])
|
593
|
+
expect(body['sessionInfo']['serverHost']).to eq('fooHost')
|
594
|
+
expect(body['events'].size).to eq(1)
|
595
|
+
expect(body['events'][0]['attrs']["serverHost"]).to eq(nil)
|
596
|
+
end
|
597
|
+
|
598
|
+
# sessionInfo serverHost always has precedence this means it's important that we don't include it if event level attribute is set, otherwise
|
599
|
+
# session level one would simply always overwrite event level one which would be ignored
|
600
|
+
it "serverHost defined in server_attributes (explicitly defined), event level serverHost defined - event level value should be used" do
|
601
|
+
config = {
|
602
|
+
'api_write_token' => '1234',
|
603
|
+
'server_attributes' => {'serverHost' => 'fooHost', 'attr1' => 'val1'}
|
604
|
+
}
|
605
|
+
plugin = LogStash::Outputs::Scalyr.new(config)
|
606
|
+
|
607
|
+
allow(plugin).to receive(:send_status).and_return(nil)
|
608
|
+
plugin.register
|
609
|
+
expect(plugin.server_attributes['serverHost']).to eq('fooHost')
|
610
|
+
|
611
|
+
e1 = LogStash::Event.new
|
612
|
+
e1.set('a1', 'v1')
|
613
|
+
e1.set('serverHost', 'event-host-1')
|
614
|
+
|
615
|
+
e2 = LogStash::Event.new
|
616
|
+
e2.set('a2', 'v2')
|
617
|
+
e2.set('serverHost', 'event-host-2')
|
618
|
+
|
619
|
+
e3 = LogStash::Event.new
|
620
|
+
e3.set('a3', 'v3')
|
621
|
+
e3.set('serverHost', 'event-host-2')
|
622
|
+
|
623
|
+
e4 = LogStash::Event.new
|
624
|
+
e4.set('a4', 'v4')
|
625
|
+
e4.set('serverHost', 'event-host-1')
|
626
|
+
|
627
|
+
result = plugin.build_multi_event_request_array([e1, e2, e3, e4])
|
628
|
+
body = JSON.parse(result[0][:body])
|
629
|
+
expect(body['sessionInfo']['serverHost']).to eq(nil)
|
630
|
+
expect(body['sessionInfo']['attr1']).to eq('val1')
|
631
|
+
|
632
|
+
expect(body['logs'].size).to eq(2)
|
633
|
+
expect(body['logs'][0]['id']).to eq(1)
|
634
|
+
expect(body['logs'][0]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq('event-host-1')
|
635
|
+
expect(body['logs'][1]['id']).to eq(2)
|
636
|
+
expect(body['logs'][1]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq('event-host-2')
|
637
|
+
|
638
|
+
expect(body['events'].size).to eq(4)
|
639
|
+
expect(body['events'][0]['log']).to eq(1)
|
640
|
+
expect(body['events'][0]['attrs']["serverHost"]).to eq(nil)
|
641
|
+
expect(body['events'][0]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq(nil)
|
642
|
+
|
643
|
+
expect(body['events'][1]['log']).to eq(2)
|
644
|
+
expect(body['events'][1]['attrs']["serverHost"]).to eq(nil)
|
645
|
+
expect(body['events'][1]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq(nil)
|
646
|
+
|
647
|
+
expect(body['events'][2]['log']).to eq(2)
|
648
|
+
expect(body['events'][2]['attrs']["serverHost"]).to eq(nil)
|
649
|
+
expect(body['events'][2]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq(nil)
|
650
|
+
|
651
|
+
expect(body['events'][3]['log']).to eq(1)
|
652
|
+
expect(body['events'][3]['attrs']["serverHost"]).to eq(nil)
|
653
|
+
expect(body['events'][3]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq(nil)
|
654
|
+
end
|
655
|
+
|
656
|
+
it "serverHost defined in server_attributes (defined via node hostname), event level serverHost defined - event level value should be used" do
|
657
|
+
config = {
|
658
|
+
'api_write_token' => '1234',
|
659
|
+
'server_attributes' => {'attr1' => 'val1'}
|
660
|
+
}
|
661
|
+
plugin = LogStash::Outputs::Scalyr.new(config)
|
662
|
+
|
663
|
+
allow(plugin).to receive(:send_status).and_return(nil)
|
664
|
+
plugin.register
|
665
|
+
|
666
|
+
expect(plugin.server_attributes['serverHost']).to eq(NODE_HOSTNAME)
|
667
|
+
|
668
|
+
e1 = LogStash::Event.new
|
669
|
+
e1.set('a1', 'v1')
|
670
|
+
e1.set('serverHost', 'event-host-1')
|
671
|
+
|
672
|
+
e2 = LogStash::Event.new
|
673
|
+
e2.set('a2', 'v2')
|
674
|
+
e2.set('serverHost', 'event-host-2')
|
675
|
+
|
676
|
+
e3 = LogStash::Event.new
|
677
|
+
e3.set('a3', 'v3')
|
678
|
+
e3.set('serverHost', 'event-host-2')
|
679
|
+
|
680
|
+
e4 = LogStash::Event.new
|
681
|
+
e4.set('a4', 'v4')
|
682
|
+
e4.set('serverHost', 'event-host-1')
|
683
|
+
|
684
|
+
result = plugin.build_multi_event_request_array([e1, e2, e3, e4])
|
685
|
+
body = JSON.parse(result[0][:body])
|
686
|
+
expect(body['sessionInfo']['serverHost']).to eq(nil)
|
687
|
+
expect(body['sessionInfo']['attr1']).to eq('val1')
|
688
|
+
|
689
|
+
expect(body['logs'].size).to eq(2)
|
690
|
+
expect(body['logs'][0]['id']).to eq(1)
|
691
|
+
expect(body['logs'][0]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq('event-host-1')
|
692
|
+
expect(body['logs'][1]['id']).to eq(2)
|
693
|
+
expect(body['logs'][1]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq('event-host-2')
|
694
|
+
|
695
|
+
expect(body['events'].size).to eq(4)
|
696
|
+
expect(body['events'][0]['log']).to eq(1)
|
697
|
+
expect(body['events'][0]['attrs']["serverHost"]).to eq(nil)
|
698
|
+
expect(body['events'][0]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq(nil)
|
699
|
+
|
700
|
+
expect(body['events'][1]['log']).to eq(2)
|
701
|
+
expect(body['events'][1]['attrs']["serverHost"]).to eq(nil)
|
702
|
+
expect(body['events'][1]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq(nil)
|
703
|
+
|
704
|
+
expect(body['events'][2]['log']).to eq(2)
|
705
|
+
expect(body['events'][2]['attrs']["serverHost"]).to eq(nil)
|
706
|
+
expect(body['events'][2]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq(nil)
|
707
|
+
|
708
|
+
expect(body['events'][3]['log']).to eq(1)
|
709
|
+
expect(body['events'][3]['attrs']["serverHost"]).to eq(nil)
|
710
|
+
expect(body['events'][3]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq(nil)
|
711
|
+
end
|
712
|
+
|
713
|
+
# If set_session_level_serverhost_on_events config option is true, we set session level serverHost on events which don't
|
714
|
+
# explicitly define this special attribute.
|
715
|
+
it "serverHost defined in server_attributes (explicitly defined), event level serverHost defined - event level value should be used and server level one for events without server host" do
|
716
|
+
config = {
|
717
|
+
'api_write_token' => '1234',
|
718
|
+
'server_attributes' => {'serverHost' => 'top-level-session-host', 'attr1' => 'val1'}
|
719
|
+
}
|
720
|
+
plugin = LogStash::Outputs::Scalyr.new(config)
|
721
|
+
|
722
|
+
allow(plugin).to receive(:send_status).and_return(nil)
|
723
|
+
plugin.register
|
724
|
+
expect(plugin.server_attributes['serverHost']).to eq('top-level-session-host')
|
725
|
+
|
726
|
+
e1 = LogStash::Event.new
|
727
|
+
e1.set('a1', 'v1')
|
728
|
+
e1.set('serverHost', 'event-host-1')
|
729
|
+
|
730
|
+
e2 = LogStash::Event.new
|
731
|
+
e2.set('a2', 'v2')
|
732
|
+
|
733
|
+
e3 = LogStash::Event.new
|
734
|
+
e3.set('a3', 'v3')
|
735
|
+
|
736
|
+
e4 = LogStash::Event.new
|
737
|
+
e4.set('a4', 'v4')
|
738
|
+
e4.set('serverHost', 'event-host-1')
|
739
|
+
|
740
|
+
result = plugin.build_multi_event_request_array([e1, e2, e3, e4])
|
741
|
+
body = JSON.parse(result[0][:body])
|
742
|
+
expect(body['sessionInfo']['serverHost']).to eq(nil)
|
743
|
+
expect(body['sessionInfo']['attr1']).to eq('val1')
|
744
|
+
|
745
|
+
expect(body['logs'].size).to eq(1)
|
746
|
+
expect(body['logs'][0]['id']).to eq(1)
|
747
|
+
expect(body['logs'][0]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq('event-host-1')
|
748
|
+
|
749
|
+
expect(body['events'].size).to eq(4)
|
750
|
+
expect(body['events'][0]['log']).to eq(1)
|
751
|
+
expect(body['events'][0]['attrs']["serverHost"]).to eq(nil)
|
752
|
+
expect(body['events'][0]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq(nil)
|
753
|
+
|
754
|
+
expect(body['events'][1]['log']).to eq(nil)
|
755
|
+
expect(body['events'][1]['attrs']["serverHost"]).to eq(nil)
|
756
|
+
expect(body['events'][2]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq("top-level-session-host")
|
757
|
+
|
758
|
+
expect(body['events'][1]['log']).to eq(nil)
|
759
|
+
expect(body['events'][2]['attrs']["serverHost"]).to eq(nil)
|
760
|
+
expect(body['events'][2]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq("top-level-session-host")
|
761
|
+
|
762
|
+
expect(body['events'][3]['log']).to eq(1)
|
763
|
+
expect(body['events'][3]['attrs']["serverHost"]).to eq(nil)
|
764
|
+
expect(body['events'][3]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq(nil)
|
765
|
+
end
|
766
|
+
|
767
|
+
it "no serverHost defined, event level serverHost defined - event level value should be used" do
|
768
|
+
config = {
|
769
|
+
'api_write_token' => '1234',
|
770
|
+
'server_attributes' => {'attr1' => 'val1'},
|
771
|
+
'use_hostname_for_serverhost' => false
|
772
|
+
}
|
773
|
+
plugin = LogStash::Outputs::Scalyr.new(config)
|
774
|
+
|
775
|
+
allow(plugin).to receive(:send_status).and_return(nil)
|
776
|
+
plugin.register
|
777
|
+
|
778
|
+
expect(plugin.server_attributes['serverHost']).to eq(nil)
|
779
|
+
|
780
|
+
e1 = LogStash::Event.new
|
781
|
+
e1.set('a1', 'v1')
|
782
|
+
e1.set('serverHost', 'event-host-1')
|
783
|
+
|
784
|
+
e2 = LogStash::Event.new
|
785
|
+
e2.set('a2', 'v2')
|
786
|
+
e2.set('serverHost', 'event-host-2')
|
787
|
+
|
788
|
+
e3 = LogStash::Event.new
|
789
|
+
e3.set('a3', 'v3')
|
790
|
+
e3.set('serverHost', 'event-host-2')
|
791
|
+
|
792
|
+
e4 = LogStash::Event.new
|
793
|
+
e4.set('a4', 'v4')
|
794
|
+
e4.set('serverHost', 'event-host-2')
|
795
|
+
|
796
|
+
result = plugin.build_multi_event_request_array([e1, e2, e3, e4])
|
797
|
+
body = JSON.parse(result[0][:body])
|
798
|
+
expect(body['sessionInfo']['serverHost']).to eq(nil)
|
799
|
+
expect(body['sessionInfo']['attr1']).to eq('val1')
|
800
|
+
|
801
|
+
expect(body['logs'][0]['id']).to eq(1)
|
802
|
+
expect(body['logs'][0]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq('event-host-1')
|
803
|
+
expect(body['logs'][1]['id']).to eq(2)
|
804
|
+
expect(body['logs'][1]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq('event-host-2')
|
805
|
+
|
806
|
+
expect(body['events'].size).to eq(4)
|
807
|
+
expect(body['events'][0]['log']).to eq(1)
|
808
|
+
expect(body['events'][0]['attrs']["serverHost"]).to eq(nil)
|
809
|
+
expect(body['events'][0]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq(nil)
|
810
|
+
expect(body['events'][1]['log']).to eq(2)
|
811
|
+
expect(body['events'][1]['attrs']["serverHost"]).to eq(nil)
|
812
|
+
expect(body['events'][1]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq(nil)
|
813
|
+
expect(body['events'][2]['log']).to eq(2)
|
814
|
+
expect(body['events'][2]['attrs']["serverHost"]).to eq(nil)
|
815
|
+
expect(body['events'][2]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq(nil)
|
816
|
+
expect(body['events'][3]['log']).to eq(2)
|
817
|
+
expect(body['events'][3]['attrs']["serverHost"]).to eq(nil)
|
818
|
+
expect(body['events'][3]['attrs'][EVENT_LEVEL_SERVER_HOST_ATTRIBUTE_NAME]).to eq(nil)
|
819
|
+
end
|
820
|
+
end
|
821
|
+
|
570
822
|
context "when receiving an event with Bignums" do
|
571
823
|
config = {
|
572
824
|
'api_write_token' => '1234',
|
@@ -585,6 +837,59 @@ describe LogStash::Outputs::Scalyr do
|
|
585
837
|
end
|
586
838
|
end
|
587
839
|
|
840
|
+
context "host attribute handling" do
|
841
|
+
it "host attribute removed by default" do
|
842
|
+
config = {
|
843
|
+
'api_write_token' => '1234',
|
844
|
+
}
|
845
|
+
plugin = LogStash::Outputs::Scalyr.new(config)
|
846
|
+
|
847
|
+
allow(plugin).to receive(:send_status).and_return(nil)
|
848
|
+
plugin.register
|
849
|
+
|
850
|
+
expect(plugin.server_attributes['serverHost']).to eq(NODE_HOSTNAME)
|
851
|
+
|
852
|
+
e1 = LogStash::Event.new
|
853
|
+
e1.set('a1', 'v1')
|
854
|
+
e1.set('host', 'event-host-1')
|
855
|
+
|
856
|
+
result = plugin.build_multi_event_request_array([e1])
|
857
|
+
body = JSON.parse(result[0][:body])
|
858
|
+
expect(body['sessionInfo']['serverHost']).to eq(NODE_HOSTNAME)
|
859
|
+
|
860
|
+
expect(body['logs'].size).to eq(0)
|
861
|
+
|
862
|
+
expect(body['events'].size).to eq(1)
|
863
|
+
expect(body['events'][0]['attrs']["host"]).to eq(nil)
|
864
|
+
end
|
865
|
+
|
866
|
+
it "host attribute not removed if config option set" do
|
867
|
+
config = {
|
868
|
+
'api_write_token' => '1234',
|
869
|
+
'remove_host_attribute_from_events' => false,
|
870
|
+
}
|
871
|
+
plugin = LogStash::Outputs::Scalyr.new(config)
|
872
|
+
|
873
|
+
allow(plugin).to receive(:send_status).and_return(nil)
|
874
|
+
plugin.register
|
875
|
+
|
876
|
+
expect(plugin.server_attributes['serverHost']).to eq(NODE_HOSTNAME)
|
877
|
+
|
878
|
+
e1 = LogStash::Event.new
|
879
|
+
e1.set('a1', 'v1')
|
880
|
+
e1.set('host', 'event-host-1')
|
881
|
+
|
882
|
+
result = plugin.build_multi_event_request_array([e1])
|
883
|
+
body = JSON.parse(result[0][:body])
|
884
|
+
expect(body['sessionInfo']['serverHost']).to eq(NODE_HOSTNAME)
|
885
|
+
|
886
|
+
expect(body['logs'].size).to eq(0)
|
887
|
+
|
888
|
+
expect(body['events'].size).to eq(1)
|
889
|
+
expect(body['events'][0]['attrs']["host"]).to eq("event-host-1")
|
890
|
+
end
|
891
|
+
end
|
892
|
+
|
588
893
|
context "when using custom json library" do
|
589
894
|
it "stdlib (implicit)" do
|
590
895
|
config = {
|
@@ -598,7 +903,7 @@ describe LogStash::Outputs::Scalyr do
|
|
598
903
|
e.set('bignumber', 20)
|
599
904
|
result = plugin.build_multi_event_request_array([e])
|
600
905
|
body = JSON.parse(result[0][:body])
|
601
|
-
expect(result[0][:body]).to include('{"monitor":"pluginLogstash"}')
|
906
|
+
expect(result[0][:body]).to include(sprintf('{"serverHost":"%s","monitor":"pluginLogstash"}', NODE_HOSTNAME))
|
602
907
|
expect(body['events'].size).to eq(1)
|
603
908
|
end
|
604
909
|
|
@@ -615,7 +920,7 @@ describe LogStash::Outputs::Scalyr do
|
|
615
920
|
e.set('bignumber', 20)
|
616
921
|
result = plugin.build_multi_event_request_array([e])
|
617
922
|
body = JSON.parse(result[0][:body])
|
618
|
-
expect(result[0][:body]).to include('{"monitor":"pluginLogstash"}')
|
923
|
+
expect(result[0][:body]).to include(sprintf('{"serverHost":"%s","monitor":"pluginLogstash"}', NODE_HOSTNAME))
|
619
924
|
expect(body['events'].size).to eq(1)
|
620
925
|
end
|
621
926
|
|
@@ -632,7 +937,7 @@ describe LogStash::Outputs::Scalyr do
|
|
632
937
|
e.set('bignumber', 20)
|
633
938
|
result = plugin.build_multi_event_request_array([e])
|
634
939
|
body = JSON.parse(result[0][:body])
|
635
|
-
expect(result[0][:body]).to include('{"monitor":"pluginLogstash"}')
|
940
|
+
expect(result[0][:body]).to include(sprintf('{"serverHost":"%s","monitor":"pluginLogstash"}', NODE_HOSTNAME))
|
636
941
|
expect(body['events'].size).to eq(1)
|
637
942
|
end
|
638
943
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-output-scalyr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0.beta
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Edward Chee
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,6 +164,7 @@ files:
|
|
164
164
|
- spec/benchmarks/flattening_and_serialization.rb
|
165
165
|
- spec/benchmarks/json_serialization.rb
|
166
166
|
- spec/benchmarks/metrics_overhead.rb
|
167
|
+
- spec/benchmarks/set_session_level_serverhost_on_events.rb
|
167
168
|
- spec/benchmarks/util.rb
|
168
169
|
- spec/logstash/outputs/scalyr_integration_spec.rb
|
169
170
|
- spec/logstash/outputs/scalyr_spec.rb
|
@@ -4097,6 +4098,7 @@ test_files:
|
|
4097
4098
|
- spec/benchmarks/flattening_and_serialization.rb
|
4098
4099
|
- spec/benchmarks/json_serialization.rb
|
4099
4100
|
- spec/benchmarks/metrics_overhead.rb
|
4101
|
+
- spec/benchmarks/set_session_level_serverhost_on_events.rb
|
4100
4102
|
- spec/benchmarks/util.rb
|
4101
4103
|
- spec/logstash/outputs/scalyr_integration_spec.rb
|
4102
4104
|
- spec/logstash/outputs/scalyr_spec.rb
|