logstash-input-signalsciences 0.3.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|