logstash-input-azure_blob_storage 0.12.5 → 0.12.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +24 -7
- data/lib/logstash/inputs/azure_blob_storage.rb +115 -29
- data/logstash-input-azure_blob_storage.gemspec +3 -4
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6bc1a46c4c6ae533e05c83f0e7cb90715cad7390a5cedb9b6e023c46f2e620d1
|
4
|
+
data.tar.gz: 520d7b5131a6b00b6de066a12cd93a99082c7af0bb7184df9f2bc9c8ca64babd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c069008cfef9b08c4b9793b24538c9c8bdc217b64285626d3c9564a57584b237bfef90f4382e4b68366c2555b1b9a6e91d897951bbcc336b355eaefb310ce00
|
7
|
+
data.tar.gz: ccb7ba1d556cec586872ebe1c94237b3223f484902218d3bff899993467b741519c521b9c08075f98328536cf31274cd2aa386f64458097b025bbef2841c486d
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
|
2
|
+
## 0.12.7
|
3
|
+
- rewrote partial_read, now the occasional json parse errors should be fixed by reading only commited blocks.
|
4
|
+
(This may also have been related to reading a second partial_read, where the offset wasn't updated correctly?)
|
5
|
+
- used the new header and tail block name, should now learn header and footer automatically again?
|
6
|
+
- added addall to the configurations to add system, mac, category, time, operation to the output
|
7
|
+
- added optional environment configuration option
|
8
|
+
- removed the date, which was always set to ---
|
9
|
+
- made a start on event rewriting to make it ECS compatibility
|
10
|
+
|
11
|
+
## 0.12.6
|
12
|
+
- Fixed the 0.12.5 exception handling, it actually caused a warning to become a fatal pipeline crashing error
|
13
|
+
- The chuck that failed to process should be printed in debug mode, for testing use debug_until => 10000
|
14
|
+
- Now check if registry entry exist before loading the offsets, to avoid caught: undefined method `[]' for nil:NilClass
|
15
|
+
|
16
|
+
## 0.12.5
|
17
|
+
- Added exception message on json parse errors
|
18
|
+
|
1
19
|
## 0.12.4
|
2
20
|
- Connection Cache reset removed, since agents are cached per host
|
3
21
|
- Explicit handling of json_lines and respecting line boundaries (thanks nttoshev)
|
data/README.md
CHANGED
@@ -42,9 +42,11 @@ input {
|
|
42
42
|
## Additional Configuration
|
43
43
|
The registry keeps track of files in the storage account, their size and how many bytes have been processed. Files can grow and the added part will be processed as a partial file. The registry is saved todisk every interval.
|
44
44
|
|
45
|
+
The interval is also defines when a new round of listing files and processing data should happen. The NSGFLOWLOG's are written every minute into a new block of the hourly blob. This data can be partially read, because the plugin knows the JSON head and tail and removes the leading comma and fixes the JSON before parsing new events
|
46
|
+
|
45
47
|
The registry_create_policy determines at the start of the pipeline if processing should resume from the last known unprocessed file, or to start_fresh ignoring old files and start only processing new events that came after the start of the pipeline. Or start_over to process all the files ignoring the registry.
|
46
48
|
|
47
|
-
interval defines the minimum time the registry should be saved to the registry file
|
49
|
+
interval defines the minimum time the registry should be saved to the registry file. By default to 'data/registry.dat' in the storageaccount, but can be also kept on the server running logstash by setting registry_local_path. The registry is kept also in memory, the registry file is only needed in case the pipeline dies unexpectedly. During a normal shutdown the registry is also saved.
|
48
50
|
|
49
51
|
When registry_local_path is set to a directory, the registry is saved on the logstash server in that directory. The filename is the pipe.id
|
50
52
|
|
@@ -66,13 +68,15 @@ The pipeline can be started in several ways.
|
|
66
68
|
```
|
67
69
|
- As managed pipeline from Kibana
|
68
70
|
|
69
|
-
Logstash itself (so not specific to this plugin) has a feature where multiple instances can run on the same system. The default TCP port is 9600, but if it's already in use it will use 9601 (and up). To update a config file on a running instance on the commandline you can add the argument --config.reload.automatic and if you modify the files that are in the pipeline.yml you can send a SIGHUP channel to reload the pipelines where the config was changed.
|
71
|
+
Logstash itself (so not specific to this plugin) has a feature where multiple instances can run on the same system. The default TCP port is 9600, but if it's already in use it will use 9601 (and up), this is probably not true anymore from v8. To update a config file on a running instance on the commandline you can add the argument --config.reload.automatic and if you modify the files that are in the pipeline.yml you can send a SIGHUP channel to reload the pipelines where the config was changed.
|
70
72
|
[https://www.elastic.co/guide/en/logstash/current/reloading-config.html](https://www.elastic.co/guide/en/logstash/current/reloading-config.html)
|
71
73
|
|
72
74
|
## Internal Working
|
73
75
|
When the plugin is started, it will read all the filenames and sizes in the blob store excluding the directies of files that are excluded by the "path_filters". After every interval it will write a registry to the storageaccount to save the information of how many bytes per blob (file) are read and processed. After all files are processed and at least one interval has passed a new file list is generated and a worklist is constructed that will be processed. When a file has already been processed before, partial files are read from the offset to the filesize at the time of the file listing. If the codec is JSON partial files will be have the header and tail will be added. They can be configured. If logtype is nsgflowlog, the plugin will process the splitting into individual tuple events. The logtype wadiis may in the future be used to process the grok formats to split into log lines. Any other format is fed into the queue as one event per file or partial file. It's then up to the filter to split and mutate the file format.
|
74
76
|
|
75
|
-
By default the root of the json message is named "message"
|
77
|
+
By default the root of the json message is named "message", you can modify the content in the filter block
|
78
|
+
|
79
|
+
Additional fields can be enabled with addfilename and addall, ecs_compatibility is not yet supported.
|
76
80
|
|
77
81
|
The configurations and the rest of the code are in [https://github.com/janmg/logstash-input-azure_blob_storage/tree/master/lib/logstash/inputs](lib/logstash/inputs) [https://github.com/janmg/logstash-input-azure_blob_storage/blob/master/lib/logstash/inputs/azure_blob_storage.rb#L10](azure_blob_storage.rb)
|
78
82
|
|
@@ -130,7 +134,7 @@ filter {
|
|
130
134
|
}
|
131
135
|
|
132
136
|
output {
|
133
|
-
stdout { }
|
137
|
+
stdout { codec => rubydebug }
|
134
138
|
}
|
135
139
|
|
136
140
|
output {
|
@@ -139,24 +143,37 @@ output {
|
|
139
143
|
index => "nsg-flow-logs-%{+xxxx.ww}"
|
140
144
|
}
|
141
145
|
}
|
146
|
+
|
147
|
+
output {
|
148
|
+
file {
|
149
|
+
path => /tmp/abuse.txt
|
150
|
+
codec => line { format => "%{decision} %{flowstate} %{src_ip} ${dst_port}"}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
142
154
|
```
|
143
155
|
A more elaborate input configuration example
|
144
156
|
```
|
145
157
|
input {
|
146
158
|
azure_blob_storage {
|
147
159
|
codec => "json"
|
148
|
-
storageaccount => "yourstorageaccountname"
|
149
|
-
access_key => "Ba5e64c0d3=="
|
160
|
+
# storageaccount => "yourstorageaccountname"
|
161
|
+
# access_key => "Ba5e64c0d3=="
|
162
|
+
connection_string => "DefaultEndpointsProtocol=https;AccountName=yourstorageaccountname;AccountKey=Ba5e64c0d3==;EndpointSuffix=core.windows.net"
|
150
163
|
container => "insights-logs-networksecuritygroupflowevent"
|
151
164
|
logtype => "nsgflowlog"
|
152
165
|
prefix => "resourceId=/"
|
153
166
|
path_filters => ['**/*.json']
|
154
167
|
addfilename => true
|
168
|
+
addall => true
|
169
|
+
environment => "dev-env"
|
155
170
|
registry_create_policy => "resume"
|
156
171
|
registry_local_path => "/usr/share/logstash/plugin"
|
157
172
|
interval => 300
|
158
173
|
debug_timer => true
|
159
|
-
debug_until =>
|
174
|
+
debug_until => 1000
|
175
|
+
addall => true
|
176
|
+
registry_create_policy => "start_over"
|
160
177
|
}
|
161
178
|
}
|
162
179
|
|
@@ -17,10 +17,12 @@ require 'json'
|
|
17
17
|
# D672f4bbd95a04209b00dc05d899e3cce 2576 json objects for 1st minute
|
18
18
|
# D7fe0d4f275a84c32982795b0e5c7d3a1 2312 json objects for 2nd minute
|
19
19
|
# Z00000000000000000000000000000000 2 ]}
|
20
|
-
|
20
|
+
#
|
21
|
+
# The azure-storage-ruby connects to the storageaccount and the files are read through get_blob. For partial read the options with start and end ar used.
|
22
|
+
# https://github.com/Azure/azure-storage-ruby/blob/master/blob/lib/azure/storage/blob/blob.rb#L89
|
23
|
+
#
|
21
24
|
# A storage account has by default a globally unique name, {storageaccount}.blob.core.windows.net which is a CNAME to Azures blob servers blob.*.store.core.windows.net. A storageaccount has an container and those have a directory and blobs (like files). Blobs have one or more blocks. After writing the blocks, they can be committed. Some Azure diagnostics can send events to an EventHub that can be parse through the plugin logstash-input-azure_event_hubs, but for the events that are only stored in an storage account, use this plugin. The original logstash-input-azureblob from azure-diagnostics-tools is great for low volumes, but it suffers from outdated client, slow reads, lease locking issues and json parse errors.
|
22
25
|
|
23
|
-
|
24
26
|
class LogStash::Inputs::AzureBlobStorage < LogStash::Inputs::Base
|
25
27
|
config_name "azure_blob_storage"
|
26
28
|
|
@@ -74,6 +76,12 @@ class LogStash::Inputs::AzureBlobStorage < LogStash::Inputs::Base
|
|
74
76
|
# add the filename as a field into the events
|
75
77
|
config :addfilename, :validate => :boolean, :default => false, :required => false
|
76
78
|
|
79
|
+
# add environment
|
80
|
+
config :environment, :validate => :string, :required => false
|
81
|
+
|
82
|
+
# add all resource details
|
83
|
+
config :addall, :validate => :boolean, :default => false, :required => false
|
84
|
+
|
77
85
|
# debug_until will at the creation of the pipeline for a maximum amount of processed messages shows 3 types of log printouts including processed filenames. After a number of events, the plugin will stop logging the events and continue silently. This is a lightweight alternative to switching the loglevel from info to debug or even trace to see what the plugin is doing and how fast at the start of the plugin. A good value would be approximately 3x the amount of events per file. For instance 6000 events.
|
78
86
|
config :debug_until, :validate => :number, :default => 0, :required => false
|
79
87
|
|
@@ -205,10 +213,12 @@ public
|
|
205
213
|
filelist = list_blobs(false)
|
206
214
|
filelist.each do |name, file|
|
207
215
|
off = 0
|
208
|
-
|
216
|
+
if @registry.key?(name) then
|
217
|
+
begin
|
209
218
|
off = @registry[name][:offset]
|
210
|
-
|
219
|
+
rescue Exception => e
|
211
220
|
@logger.error("caught: #{e.message} while reading #{name}")
|
221
|
+
end
|
212
222
|
end
|
213
223
|
@registry.store(name, { :offset => off, :length => file[:length] })
|
214
224
|
if (@debug_until > @processed) then @logger.info("2: adding offsets: #{name} #{off} #{file[:length]}") end
|
@@ -258,9 +268,8 @@ public
|
|
258
268
|
delta_size = 0
|
259
269
|
end
|
260
270
|
else
|
261
|
-
chunk =
|
262
|
-
delta_size = chunk.size
|
263
|
-
@logger.debug("partial file #{name} from #{file[:offset]} to #{file[:length]}")
|
271
|
+
chunk = partial_read(name, file[:offset])
|
272
|
+
delta_size = chunk.size - @head.length - 1
|
264
273
|
end
|
265
274
|
|
266
275
|
if logtype == "nsgflowlog" && @is_json
|
@@ -270,14 +279,13 @@ public
|
|
270
279
|
begin
|
271
280
|
fingjson = JSON.parse(chunk)
|
272
281
|
@processed += nsgflowlog(queue, fingjson, name)
|
273
|
-
@logger.debug("Processed #{res[:nsg]}
|
274
|
-
rescue JSON::ParserError
|
275
|
-
@logger.error("parse error #{e.message} on #{res[:nsg]}
|
276
|
-
@logger.
|
282
|
+
@logger.debug("Processed #{res[:nsg]} #{@processed} events")
|
283
|
+
rescue JSON::ParserError => e
|
284
|
+
@logger.error("parse error #{e.message} on #{res[:nsg]} offset: #{file[:offset]} length: #{file[:length]}")
|
285
|
+
if (@debug_until > @processed) then @logger.info("#{chunk}") end
|
277
286
|
end
|
278
287
|
end
|
279
288
|
# TODO: Convert this to line based grokking.
|
280
|
-
# TODO: ECS Compliance?
|
281
289
|
elsif logtype == "wadiis" && !@is_json
|
282
290
|
@processed += wadiislog(queue, name)
|
283
291
|
else
|
@@ -396,14 +404,35 @@ private
|
|
396
404
|
return chuck
|
397
405
|
end
|
398
406
|
|
399
|
-
def
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
407
|
+
def partial_read(blobname, offset)
|
408
|
+
# 1. read committed blocks, calculate length
|
409
|
+
# 2. calculate the offset to read
|
410
|
+
# 3. strip comma
|
411
|
+
# if json strip comma and fix head and tail
|
412
|
+
size = 0
|
413
|
+
blocks = @blob_client.list_blob_blocks(container, blobname)
|
414
|
+
blocks[:committed].each do |block|
|
415
|
+
size += block.size
|
416
|
+
end
|
417
|
+
# read the new blob blocks from the offset to the last committed size.
|
418
|
+
# if it is json, fix the head and tail
|
419
|
+
# crap committed block at the end is the tail, so must be substracted from the read and then comma stripped and tail added.
|
420
|
+
# but why did I need a -1 for the length?? probably the offset starts at 0 and ends at size-1
|
421
|
+
|
422
|
+
# should first check commit, read and the check committed again? no, only read the commited size
|
423
|
+
# should read the full content and then substract json tail
|
424
|
+
|
425
|
+
if @is_json
|
426
|
+
content = @blob_client.get_blob(container, blobname, start_range: offset-1, end_range: size-1)[1]
|
427
|
+
if content.end_with?(@tail)
|
428
|
+
return @head + strip_comma(content)
|
429
|
+
else
|
430
|
+
@logger.info("Fixed a tail! probably new committed blocks started appearing!")
|
431
|
+
# substract the length of the tail and add the tail, because the file grew.size was calculated as the block boundary, so replacing the last bytes with the tail should fix the problem
|
432
|
+
return @head + strip_comma(content[0...-@tail.length]) + @tail
|
433
|
+
end
|
404
434
|
else
|
405
|
-
|
406
|
-
return @head + strip_comma(content[0...-@tail.length]) + @tail
|
435
|
+
content = @blob_client.get_blob(container, blobname, start_range: offset, end_range: size-1)[1]
|
407
436
|
end
|
408
437
|
end
|
409
438
|
|
@@ -420,8 +449,9 @@ private
|
|
420
449
|
count=0
|
421
450
|
begin
|
422
451
|
json["records"].each do |record|
|
423
|
-
|
424
|
-
resource = { :subscription => res[:subscription], :resourcegroup => res[:resourcegroup], :nsg => res[:nsg] }
|
452
|
+
resource = resource(record["resourceId"])
|
453
|
+
# resource = { :subscription => res[:subscription], :resourcegroup => res[:resourcegroup], :nsg => res[:nsg] }
|
454
|
+
extras = { :time => record["time"], :system => record["systemId"], :mac => record["macAddress"], :category => record["category"], :operation => record["operationName"] }
|
425
455
|
@logger.trace(resource.to_s)
|
426
456
|
record["properties"]["flows"].each do |flows|
|
427
457
|
rule = resource.merge ({ :rule => flows["rule"]})
|
@@ -440,7 +470,18 @@ private
|
|
440
470
|
if @addfilename
|
441
471
|
ev.merge!( {:filename => name } )
|
442
472
|
end
|
473
|
+
unless @environment.nil?
|
474
|
+
ev.merge!( {:environment => environment } )
|
475
|
+
end
|
476
|
+
if @addall
|
477
|
+
ev.merge!( extras )
|
478
|
+
end
|
479
|
+
|
480
|
+
# Add event to logstash queue
|
443
481
|
event = LogStash::Event.new('message' => ev.to_json)
|
482
|
+
#if @ecs_compatibility != "disabled"
|
483
|
+
# event = ecs(event)
|
484
|
+
#end
|
444
485
|
decorate(event)
|
445
486
|
queue << event
|
446
487
|
count+=1
|
@@ -561,11 +602,11 @@ private
|
|
561
602
|
unless blob.name == registry_path
|
562
603
|
begin
|
563
604
|
blocks = @blob_client.list_blob_blocks(container, blob.name)[:committed]
|
564
|
-
if blocks.first.name
|
605
|
+
if ['A00000000000000000000000000000000','QTAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw'].include?(blocks.first.name)
|
565
606
|
@logger.debug("using #{blob.name}/#{blocks.first.name} to learn the json header")
|
566
607
|
@head = @blob_client.get_blob(container, blob.name, start_range: 0, end_range: blocks.first.size-1)[1]
|
567
608
|
end
|
568
|
-
if blocks.last.name
|
609
|
+
if ['Z00000000000000000000000000000000','WjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw'].include?(blocks.last.name)
|
569
610
|
@logger.debug("using #{blob.name}/#{blocks.last.name} to learn the json footer")
|
570
611
|
length = blob.properties[:content_length].to_i
|
571
612
|
offset = length - blocks.last.size
|
@@ -573,7 +614,7 @@ private
|
|
573
614
|
@logger.debug("learned tail: #{@tail}")
|
574
615
|
end
|
575
616
|
rescue Exception => e
|
576
|
-
@logger.info("learn json one of the attempts failed
|
617
|
+
@logger.info("learn json one of the attempts failed")
|
577
618
|
end
|
578
619
|
end
|
579
620
|
end
|
@@ -584,15 +625,60 @@ private
|
|
584
625
|
|
585
626
|
def resource(str)
|
586
627
|
temp = str.split('/')
|
587
|
-
date = '---'
|
588
|
-
unless temp[9].nil?
|
589
|
-
|
590
|
-
end
|
591
|
-
return {:subscription=> temp[2], :resourcegroup=>temp[4], :nsg=>temp[8]
|
628
|
+
#date = '---'
|
629
|
+
#unless temp[9].nil?
|
630
|
+
# date = val(temp[9])+'/'+val(temp[10])+'/'+val(temp[11])+'-'+val(temp[12])+':00'
|
631
|
+
#end
|
632
|
+
return {:subscription=> temp[2], :resourcegroup=>temp[4], :nsg=>temp[8]}
|
592
633
|
end
|
593
634
|
|
594
635
|
def val(str)
|
595
636
|
return str.split('=')[1]
|
596
637
|
end
|
597
638
|
|
639
|
+
=begin
|
640
|
+
def ecs(old)
|
641
|
+
# https://www.elastic.co/guide/en/ecs/current/ecs-field-reference.html
|
642
|
+
ecs = LogStash::Event.new()
|
643
|
+
ecs.set("ecs.version", "1.0.0")
|
644
|
+
ecs.set("@timestamp", old.timestamp)
|
645
|
+
ecs.set("cloud.provider", "azure")
|
646
|
+
ecs.set("cloud.account.id", old.get("[subscription]")
|
647
|
+
ecs.set("cloud.project.id", old.get("[environment]")
|
648
|
+
ecs.set("file.name", old.get("[filename]")
|
649
|
+
ecs.set("event.category", "network")
|
650
|
+
if old.get("[decision]") == "D"
|
651
|
+
ecs.set("event.type", "denied")
|
652
|
+
else
|
653
|
+
ecs.set("event.type", "allowed")
|
654
|
+
end
|
655
|
+
ecs.set("event.action", "")
|
656
|
+
ecs.set("rule.ruleset", old.get("[nsg]")
|
657
|
+
ecs.set("rule.name", old.get("[rule]")
|
658
|
+
ecs.set("trace.id", old.get("[protocol]")+"/"+old.get("[src_ip]")+":"+old.get("[src_port]")+"-"+old.get("[dst_ip]")+":"+old.get("[dst_port]")
|
659
|
+
# requires logic to match sockets and flip src/dst for outgoing.
|
660
|
+
ecs.set("host.mac", old.get("[mac]")
|
661
|
+
ecs.set("source.ip", old.get("[src_ip]")
|
662
|
+
ecs.set("source.port", old.get("[src_port]")
|
663
|
+
ecs.set("source.bytes", old.get("[srcbytes]")
|
664
|
+
ecs.set("source.packets", old.get("[src_pack]")
|
665
|
+
ecs.set("destination.ip", old.get("[dst_ip]")
|
666
|
+
ecs.set("destination.port", old.get("[dst_port]")
|
667
|
+
ecs.set("destination.bytes", old.get("[dst_bytes]")
|
668
|
+
ecs.set("destination.packets", old.get("[dst_packets]")
|
669
|
+
if old.get("[protocol]") = "U"
|
670
|
+
ecs.set("network.transport", "udp")
|
671
|
+
else
|
672
|
+
ecs.set("network.transport", "tcp")
|
673
|
+
end
|
674
|
+
if old.get("[decision]") == "I"
|
675
|
+
ecs.set("network.direction", "incoming")
|
676
|
+
else
|
677
|
+
ecs.set("network.direction", "outgoing")
|
678
|
+
end
|
679
|
+
ecs.set("network.bytes", old.get("[src_bytes]")+old.get("[dst_bytes]")
|
680
|
+
ecs.set("network.packets", old.get("[src_packets]")+old.get("[dst_packets]")
|
681
|
+
return ecs
|
682
|
+
end
|
683
|
+
=end
|
598
684
|
end # class LogStash::Inputs::AzureBlobStorage
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'logstash-input-azure_blob_storage'
|
3
|
-
s.version = '0.12.
|
3
|
+
s.version = '0.12.7'
|
4
4
|
s.licenses = ['Apache-2.0']
|
5
5
|
s.summary = 'This logstash plugin reads and parses data from Azure Storage Blobs.'
|
6
6
|
s.description = <<-EOF
|
@@ -23,7 +23,6 @@ EOF
|
|
23
23
|
s.add_runtime_dependency 'logstash-core-plugin-api', '~> 2.0'
|
24
24
|
s.add_runtime_dependency 'stud', '~> 0.0.23'
|
25
25
|
s.add_runtime_dependency 'azure-storage-blob', '~> 2', '>= 2.0.3'
|
26
|
-
|
27
|
-
s.add_development_dependency '
|
28
|
-
s.add_development_dependency 'rubocop'
|
26
|
+
s.add_development_dependency 'logstash-devutils', '~> 2.4'
|
27
|
+
s.add_development_dependency 'rubocop', '~> 1.48'
|
29
28
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-input-azure_blob_storage
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.
|
4
|
+
version: 0.12.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Geertsma
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -61,31 +61,31 @@ dependencies:
|
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
requirement: !ruby/object:Gem::Requirement
|
63
63
|
requirements:
|
64
|
-
- - "
|
64
|
+
- - "~>"
|
65
65
|
- !ruby/object:Gem::Version
|
66
|
-
version: '
|
66
|
+
version: '2.4'
|
67
67
|
name: logstash-devutils
|
68
68
|
prerelease: false
|
69
69
|
type: :development
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
|
-
- - "
|
72
|
+
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version: '
|
74
|
+
version: '2.4'
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
requirement: !ruby/object:Gem::Requirement
|
77
77
|
requirements:
|
78
|
-
- - "
|
78
|
+
- - "~>"
|
79
79
|
- !ruby/object:Gem::Version
|
80
|
-
version: '
|
80
|
+
version: '1.48'
|
81
81
|
name: rubocop
|
82
82
|
prerelease: false
|
83
83
|
type: :development
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
|
-
- - "
|
86
|
+
- - "~>"
|
87
87
|
- !ruby/object:Gem::Version
|
88
|
-
version: '
|
88
|
+
version: '1.48'
|
89
89
|
description: " This gem is a Logstash plugin. It reads and parses data from Azure\
|
90
90
|
\ Storage Blobs. The azure_blob_storage is a reimplementation to replace azureblob\
|
91
91
|
\ from azure-diagnostics-tools/Logstash. It can deal with larger volumes and partial\
|