logstash-input-signalsciences 0.3.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/logstash/inputs/signalsciences.rb +134 -94
- data/logstash-input-signalsciences.gemspec +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49e1f0ae15ed2dc2b8d8fb079c3d6de416b3d7fc
|
4
|
+
data.tar.gz: 011cc2201fc62fea29b465e22f73b5203205e055
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6a2fb3ac45c9b8435bea206baa4b40306deaa069dd471cdb7aeadba859cab51a25fc89dcfc7bb74d4718ef932b71b73ba1e0f28a7943e62993b21436ddc83ce
|
7
|
+
data.tar.gz: c2c8c28854869195dcb9ec9a02b2c1bb08af6307cbd105149f1cf089181f35011e28d659b2aa6127835fcb16662b168990425b8320cc0946a64c53c480b74e00
|
@@ -19,7 +19,9 @@ class LogStash::Inputs::Signalsciences < LogStash::Inputs::Base
|
|
19
19
|
# Signal Sciences API account username.
|
20
20
|
config :email, :validate => :string, :default => "nobody@signalsciences.com"
|
21
21
|
# Signal Sciences API password.
|
22
|
-
config :password, :validate => :string, :default => "
|
22
|
+
config :password, :validate => :string, :default => ""
|
23
|
+
# Signal Sciences API access token.
|
24
|
+
config :token, :validate => :string, :default => ""
|
23
25
|
# Corp and site to pull data from.
|
24
26
|
config :corp, :validate => :string, :default => "not_provided"
|
25
27
|
config :site, :validate => :string, :default => "not_provided"
|
@@ -37,9 +39,15 @@ class LogStash::Inputs::Signalsciences < LogStash::Inputs::Base
|
|
37
39
|
@http = Net::HTTP.new('dashboard.signalsciences.net', 443)
|
38
40
|
@http.set_debug_output($stdout) if @debug
|
39
41
|
@login = Net::HTTP::Post.new("/api/v0/auth")
|
42
|
+
@auth_mode = "password"
|
40
43
|
@get = Net::HTTP::Get.new("/api/v0/corps/#{@corp}/sites/#{@site}/feed/requests")
|
41
44
|
@http.use_ssl = true
|
42
45
|
|
46
|
+
# determine authentication mode
|
47
|
+
if @token != ""
|
48
|
+
@auth_mode = "token"
|
49
|
+
end
|
50
|
+
|
43
51
|
# check if from value is less than 1 min
|
44
52
|
if @from < 60
|
45
53
|
@logger.warn("from value is less than 1 min, increasing from value to 1 minute.")
|
@@ -56,7 +64,7 @@ class LogStash::Inputs::Signalsciences < LogStash::Inputs::Base
|
|
56
64
|
@interval = @from
|
57
65
|
|
58
66
|
# set version for UA string
|
59
|
-
@version = "0.
|
67
|
+
@version = "1.0.0"
|
60
68
|
|
61
69
|
@logger.info("Fetching Signal Sciences request data every #{@interval / 60} minutes.")
|
62
70
|
end # def register
|
@@ -64,8 +72,10 @@ class LogStash::Inputs::Signalsciences < LogStash::Inputs::Base
|
|
64
72
|
def run(queue)
|
65
73
|
# we can abort the loop if stop? becomes true
|
66
74
|
while !stop?
|
67
|
-
@
|
68
|
-
|
75
|
+
if @auth_mode == "password"
|
76
|
+
@login['User-Agent'] = "logstash-signalsciences/#{@version}"
|
77
|
+
@login.body = URI.encode_www_form({"email" => @email, "password" => @password})
|
78
|
+
end
|
69
79
|
|
70
80
|
if fetch(queue)
|
71
81
|
@logger.info("Requests feed retreived successfully.")
|
@@ -84,112 +94,142 @@ class LogStash::Inputs::Signalsciences < LogStash::Inputs::Base
|
|
84
94
|
end # def run
|
85
95
|
|
86
96
|
def fetch(queue)
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
97
|
+
if @auth_mode == "password"
|
98
|
+
begin
|
99
|
+
response = @http.request(@login)
|
100
|
+
@logger.warn("login response: #{response.code}")
|
101
|
+
rescue
|
102
|
+
@logger.warn("Could not reach API endpoint to login!")
|
103
|
+
return false
|
104
|
+
end
|
105
|
+
|
106
|
+
json = JSON.parse(response.body)
|
107
|
+
|
108
|
+
if json.has_key? "message"
|
109
|
+
# failed to login
|
110
|
+
@logger.warn("login: #{json['message']}")
|
111
|
+
return false
|
112
|
+
end
|
113
|
+
|
114
|
+
bearer_token = json['token']
|
93
115
|
end
|
94
116
|
|
95
|
-
|
117
|
+
|
118
|
+
# Both the from and until parameters must fall on full minute boundaries,
|
119
|
+
# see https://docs.signalsciences.net/faq/extract-your-data/.
|
120
|
+
t = Time.now.utc.strftime("%Y-%m-%d %H:%M:0")
|
121
|
+
dt = DateTime.parse(t)
|
122
|
+
timestamp_until = dt.to_time.to_i - 300 # now - 5 minutes
|
123
|
+
timestamp_from = (timestamp_until - @from) # @until - @from
|
124
|
+
|
125
|
+
if @debug
|
126
|
+
hfrom = Time.at(timestamp_from).to_datetime
|
127
|
+
huntil = Time.at(timestamp_until).to_datetime
|
128
|
+
@logger.info("From #{hfrom} Until #{huntil}")
|
129
|
+
end
|
96
130
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
131
|
+
# Set up iniital get request and initial next_uri
|
132
|
+
@logger.info("Requesting data: /api/v0/corps/#{@corp}/sites/#{@site}/feed/requests?from=#{timestamp_from}&until=#{timestamp_until}")
|
133
|
+
get = Net::HTTP::Get.new("/api/v0/corps/#{@corp}/sites/#{@site}/feed/requests?from=#{timestamp_from}&until=#{timestamp_until}")
|
134
|
+
next_uri = "not empty on first pass"
|
101
135
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
136
|
+
# Loop through results until next_uri is empty.
|
137
|
+
while !next_uri.empty?
|
138
|
+
if @auth_mode == "password"
|
139
|
+
get["Authorization"] = "Bearer #{bearer_token}"
|
140
|
+
else
|
141
|
+
get["x-api-user"] = @email
|
142
|
+
get["x-api-token"] = @token
|
143
|
+
end
|
144
|
+
get['User-Agent'] = "logstash-signalsciences/#{@version}"
|
110
145
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
@logger.
|
146
|
+
begin
|
147
|
+
response = @http.request(get)
|
148
|
+
rescue
|
149
|
+
@logger.warn("Could not reach API endpoint to retreive reqeusts feed!")
|
150
|
+
return false
|
151
|
+
end
|
152
|
+
|
153
|
+
if response.code == "524"
|
154
|
+
@logger.warn("524 - Origin Timeout!")
|
155
|
+
@logger.info("Another attempt will be made later.")
|
156
|
+
return false
|
157
|
+
end
|
158
|
+
|
159
|
+
if response.code == "429"
|
160
|
+
@logger.warn("429 - Too Many Requests!")
|
161
|
+
@logger.info("API request throttling as been triggered, another attempt will be made later. Contact support if this error continues.")
|
162
|
+
return false
|
163
|
+
end
|
164
|
+
|
165
|
+
if response.code == "404"
|
166
|
+
@logger.warn("404 - Not Found!")
|
167
|
+
return false
|
115
168
|
end
|
116
169
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
170
|
+
if response.code == "401"
|
171
|
+
@logger.warn("401 - Unauthorized!")
|
172
|
+
return false
|
173
|
+
end
|
174
|
+
|
175
|
+
json = JSON.parse(response.body)
|
121
176
|
|
122
|
-
#
|
123
|
-
|
124
|
-
|
125
|
-
|
177
|
+
#check for message, error, e.g. missing query string parameter
|
178
|
+
if json.has_key? "message"
|
179
|
+
# some error occured, report it.
|
180
|
+
@logger.warn("Error accessing API (auth mode: #{@auth_mode}), status code: #{response.code} with message: #{json['message']}")
|
181
|
+
return false
|
182
|
+
end
|
126
183
|
|
184
|
+
# log json payloads
|
185
|
+
json['data'].each do |payload|
|
186
|
+
|
187
|
+
# explode headersIn out to headerIn entries
|
188
|
+
temp = {}
|
127
189
|
begin
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
json = JSON.parse(response.body)
|
134
|
-
|
135
|
-
#check for message, error, e.g. missing query string parameter
|
136
|
-
if json.has_key? "message"
|
137
|
-
# some error occured, report it.
|
138
|
-
@logger.warn("Error accessing API (#{token}), status code: #{response.code} with message: #{json['message']}")
|
139
|
-
return false
|
140
|
-
|
141
|
-
else
|
142
|
-
# log json payloads
|
143
|
-
json['data'].each do |payload|
|
144
|
-
|
145
|
-
# explode headersIn out to headerIn entries
|
146
|
-
temp = {}
|
147
|
-
begin
|
148
|
-
payload['headersIn'].each { |k,v| temp[k] = v }
|
149
|
-
payload["headerIn"] = temp
|
150
|
-
rescue NoMethodError
|
151
|
-
if @debug
|
152
|
-
@logger.debug("payload['headersIn'] is empty for id #{payload['id']}, skipping append.")
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
# explode headersOut out to headerOut entries
|
157
|
-
temp = {}
|
158
|
-
begin
|
159
|
-
payload['headersOut'].each { |k,v| temp[k] = v }
|
160
|
-
payload["headerOut"] = temp
|
161
|
-
rescue NoMethodError
|
162
|
-
if @debug
|
163
|
-
@logger.info("payload['headersOut'] is empty for id #{payload['id']}, skipping append.")
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
# explode tags out to tag entries
|
168
|
-
temp = {}
|
169
|
-
payload['tags'].each do |x|
|
170
|
-
temp[x['type']] = x
|
171
|
-
end
|
172
|
-
payload['tag'] = temp
|
173
|
-
|
174
|
-
# add the event
|
175
|
-
|
176
|
-
event = LogStash::Event.new("message" => payload, "host" => @host)
|
177
|
-
|
178
|
-
decorate(event)
|
179
|
-
queue << event
|
190
|
+
payload['headersIn'].each { |k,v| temp[k] = v }
|
191
|
+
payload["headerIn"] = temp
|
192
|
+
rescue NoMethodError
|
193
|
+
if @debug
|
194
|
+
@logger.debug("payload['headersIn'] is empty for id #{payload['id']}, skipping append.")
|
180
195
|
end
|
196
|
+
end
|
181
197
|
|
182
|
-
|
183
|
-
|
198
|
+
# explode headersOut out to headerOut entries
|
199
|
+
temp = {}
|
200
|
+
begin
|
201
|
+
payload['headersOut'].each { |k,v| temp[k] = v }
|
202
|
+
payload["headerOut"] = temp
|
203
|
+
rescue NoMethodError
|
184
204
|
if @debug
|
185
|
-
logger.info("
|
205
|
+
@logger.info("payload['headersOut'] is empty for id #{payload['id']}, skipping append.")
|
186
206
|
end
|
207
|
+
end
|
187
208
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
209
|
+
# explode tags out to tag entries
|
210
|
+
temp = {}
|
211
|
+
payload['tags'].each do |x|
|
212
|
+
temp[x['type']] = x
|
192
213
|
end
|
214
|
+
payload['tag'] = temp
|
215
|
+
|
216
|
+
# add the event
|
217
|
+
|
218
|
+
event = LogStash::Event.new("message" => payload, "host" => @host)
|
219
|
+
|
220
|
+
decorate(event)
|
221
|
+
queue << event
|
222
|
+
end
|
223
|
+
|
224
|
+
# get the next uri value
|
225
|
+
next_uri = json['next']['uri']
|
226
|
+
if @debug
|
227
|
+
logger.info("Next URI: #{next_uri}")
|
228
|
+
end
|
229
|
+
|
230
|
+
# continue retreiving next_uri if it exists
|
231
|
+
if !next_uri.empty?
|
232
|
+
get = Net::HTTP::Get.new(next_uri)
|
193
233
|
end
|
194
234
|
end
|
195
235
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'logstash-input-signalsciences'
|
3
|
-
s.version = '0.
|
3
|
+
s.version = '1.0.0'
|
4
4
|
s.licenses = ['Apache-2.0']
|
5
5
|
s.summary = 'Logstash input plugin for Signal Sciences.'
|
6
6
|
s.description = 'Logstash input plugin for the Signal Sciences request feed endpoint https://docs.signalsciences.net/api/#get-request-feed'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-input-signalsciences
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- foospidy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02-
|
11
|
+
date: 2020-02-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: logstash-core-plugin-api
|