logstash-input-twitter 2.0.2 → 2.1.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/CHANGELOG.md +10 -0
- data/README.md +3 -0
- data/lib/logstash/inputs/twitter.rb +130 -30
- data/logstash-input-twitter.gemspec +2 -2
- data/spec/inputs/twitter_spec.rb +176 -12
- data/spec/integration/twitter_spec.rb +75 -0
- data/spec/spec_helper.rb +19 -0
- metadata +35 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c2c82687f3ddd3386c346f11cead1cd3a6bbc485
|
4
|
+
data.tar.gz: 8ba300f93af4f14852047a19f1187fc72f0cda80
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5f37dde1ba6376d57f4d4064b7f9ddcadaa7ada41449f6abfd80dc9a51b852981bbee2fc9566d38ad3bdc0badba1689ec6520bc801d90353fc55e22a1569fe4
|
7
|
+
data.tar.gz: f7bd667faadaa77c6e41f53785dc807e2764ae20c65276023ca7297d1108cf6479326501d248e778a463df89372db55a5d2dc648f3ab41795fe56c633e3f62cd
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 2.1.0
|
2
|
+
- Add an option to fetch data from the sample endpoint.
|
3
|
+
- Add hashtags, symbols and user_mentions as data for the non extended tweet event.
|
4
|
+
- Add an option to filter per location and language.
|
5
|
+
- Add an option to stream data from a list of users.
|
6
|
+
- Add integration and unit tests for this and previous features.
|
7
|
+
- Add an ignore_retweet flag to filter them.
|
8
|
+
- Small code reorg and refactoring.
|
9
|
+
- Fixes #22 #21 #20 #11 #9
|
10
|
+
|
1
11
|
## 2.0.0
|
2
12
|
- Plugins were updated to follow the new shutdown semantic, this mainly allows Logstash to instruct input plugins to terminate gracefully,
|
3
13
|
instead of using Thread.raise on the plugins' threads. Ref: https://github.com/elastic/logstash/pull/3895
|
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Logstash Plugin
|
2
2
|
|
3
|
+
[](http://build-eu-00.elastic.co/view/LS%20Plugins/view/LS%20Inputs/job/logstash-plugin-input-twitter-unit/)
|
5
|
+
|
3
6
|
This is a plugin for [Logstash](https://github.com/elastic/logstash).
|
4
7
|
|
5
8
|
It is fully free and fully open source. The license is Apache 2.0, meaning you are pretty much free to use it however you want in whatever way.
|
@@ -6,27 +6,29 @@ require "logstash/util"
|
|
6
6
|
require "logstash/json"
|
7
7
|
require "stud/interval"
|
8
8
|
|
9
|
-
#
|
9
|
+
# Ingest events from the Twitter Streaming API.
|
10
10
|
class LogStash::Inputs::Twitter < LogStash::Inputs::Base
|
11
11
|
|
12
|
+
attr_reader :filter_options
|
13
|
+
|
12
14
|
config_name "twitter"
|
13
15
|
|
14
|
-
# Your
|
16
|
+
# Your Twitter App's consumer key
|
15
17
|
#
|
16
18
|
# Don't know what this is? You need to create an "application"
|
17
|
-
# on
|
19
|
+
# on Twitter, see this url: <https://dev.twitter.com/apps/new>
|
18
20
|
config :consumer_key, :validate => :string, :required => true
|
19
21
|
|
20
|
-
# Your
|
22
|
+
# Your Twitter App's consumer secret
|
21
23
|
#
|
22
24
|
# If you don't have one of these, you can create one by
|
23
|
-
# registering a new application with
|
25
|
+
# registering a new application with Twitter:
|
24
26
|
# <https://dev.twitter.com/apps/new>
|
25
27
|
config :consumer_secret, :validate => :password, :required => true
|
26
28
|
|
27
29
|
# Your oauth token.
|
28
30
|
#
|
29
|
-
# To get this, login to
|
31
|
+
# To get this, login to Twitter with whatever account you want,
|
30
32
|
# then visit <https://dev.twitter.com/apps>
|
31
33
|
#
|
32
34
|
# Click on your app (used with the consumer_key and consumer_secret settings)
|
@@ -37,7 +39,7 @@ class LogStash::Inputs::Twitter < LogStash::Inputs::Base
|
|
37
39
|
|
38
40
|
# Your oauth token secret.
|
39
41
|
#
|
40
|
-
# To get this, login to
|
42
|
+
# To get this, login to Twitter with whatever account you want,
|
41
43
|
# then visit <https://dev.twitter.com/apps>
|
42
44
|
#
|
43
45
|
# Click on your app (used with the consumer_key and consumer_secret settings)
|
@@ -46,20 +48,57 @@ class LogStash::Inputs::Twitter < LogStash::Inputs::Base
|
|
46
48
|
# application.
|
47
49
|
config :oauth_token_secret, :validate => :password, :required => true
|
48
50
|
|
49
|
-
# Any keywords to track in the
|
50
|
-
|
51
|
+
# Any keywords to track in the Twitter stream. For multiple keywords, use
|
52
|
+
# the syntax ["foo", "bar"]. There's a logical OR between each keyword
|
53
|
+
# string listed and a logical AND between words separated by spaces per
|
54
|
+
# keyword string.
|
55
|
+
# See https://dev.twitter.com/streaming/overview/request-parameters#track
|
56
|
+
# for more details.
|
57
|
+
#
|
58
|
+
# The wildcard "*" option is not supported. To ingest a sample stream of
|
59
|
+
# all tweets, the use_samples option is recommended.
|
60
|
+
config :keywords, :validate => :array
|
51
61
|
|
52
|
-
# Record full tweet object as given to us by the Twitter
|
62
|
+
# Record full tweet object as given to us by the Twitter Streaming API.
|
53
63
|
config :full_tweet, :validate => :boolean, :default => false
|
54
64
|
|
55
|
-
|
65
|
+
# A comma separated list of user IDs, indicating the users to
|
66
|
+
# return statuses for in the Twitter stream.
|
67
|
+
# See https://dev.twitter.com/streaming/overview/request-parameters#follow
|
68
|
+
# for more details.
|
69
|
+
config :follows, :validate => :array
|
70
|
+
|
71
|
+
# A comma-separated list of longitude, latitude pairs specifying a set
|
72
|
+
# of bounding boxes to filter tweets by.
|
73
|
+
# See https://dev.twitter.com/streaming/overview/request-parameters#locations
|
74
|
+
# for more details.
|
75
|
+
config :locations, :validate => :string
|
76
|
+
|
77
|
+
# A list of BCP 47 language identifiers corresponding to any of the languages listed
|
78
|
+
# on Twitter’s advanced search page will only return tweets that have been detected
|
79
|
+
# as being written in the specified languages.
|
80
|
+
config :languages, :validate => :array
|
81
|
+
|
82
|
+
# Returns a small random sample of all public statuses. The tweets returned
|
83
|
+
# by the default access level are the same, so if two different clients connect
|
84
|
+
# to this endpoint, they will see the same tweets. If set to true, the keywords,
|
85
|
+
# follows, locations, and languages options will be ignored. Default => false
|
86
|
+
config :use_samples, :validate => :boolean, :default => false
|
87
|
+
|
88
|
+
# Lets you ingore the retweets coming out of the Twitter API. Default => false
|
89
|
+
config :ignore_retweets, :validate => :boolean, :default => false
|
90
|
+
|
56
91
|
def register
|
57
92
|
require "twitter"
|
58
93
|
|
94
|
+
if !@use_samples && ( @keywords.nil? && @follows.nil? && @locations.nil? )
|
95
|
+
raise LogStash::ConfigurationError.new("At least one parameter (follows, locations or keywords) must be specified.")
|
96
|
+
end
|
97
|
+
|
59
98
|
# monkey patch twitter gem to ignore json parsing error.
|
60
99
|
# at the same time, use our own json parser
|
61
100
|
# this has been tested with a specific gem version, raise if not the same
|
62
|
-
raise("Incompatible Twitter gem version and the LogStash::Json.load") unless Twitter::Version.to_s == "5.
|
101
|
+
raise("Incompatible Twitter gem version and the LogStash::Json.load") unless Twitter::Version.to_s == "5.14.0"
|
63
102
|
|
64
103
|
Twitter::Streaming::Response.module_eval do
|
65
104
|
def on_body(data)
|
@@ -74,51 +113,83 @@ class LogStash::Inputs::Twitter < LogStash::Inputs::Base
|
|
74
113
|
end
|
75
114
|
end
|
76
115
|
|
77
|
-
@
|
78
|
-
|
79
|
-
|
80
|
-
c.access_token = @oauth_token
|
81
|
-
c.access_token_secret = @oauth_token_secret.value
|
82
|
-
end
|
116
|
+
@rest_client = Twitter::REST::Client.new { |c| configure(c) }
|
117
|
+
@stream_client = Twitter::Streaming::Client.new { |c| configure(c) }
|
118
|
+
@twitter_options = build_options
|
83
119
|
end
|
84
120
|
|
85
|
-
public
|
86
121
|
def run(queue)
|
87
|
-
@logger.info("Starting twitter tracking",
|
122
|
+
@logger.info("Starting twitter tracking", twitter_options.clone) # need to pass a clone as it modify this var otherwise
|
88
123
|
begin
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
decorate(event)
|
94
|
-
queue << event
|
124
|
+
if @use_samples
|
125
|
+
@stream_client.sample do |tweet|
|
126
|
+
return if stop?
|
127
|
+
tweet_processor(queue, tweet)
|
95
128
|
end
|
96
|
-
|
129
|
+
else
|
130
|
+
@stream_client.filter(twitter_options) do |tweet|
|
131
|
+
return if stop?
|
132
|
+
tweet_processor(queue, tweet)
|
133
|
+
end
|
134
|
+
end
|
97
135
|
rescue Twitter::Error::TooManyRequests => e
|
98
136
|
@logger.warn("Twitter too many requests error, sleeping for #{e.rate_limit.reset_in}s")
|
99
137
|
Stud.stoppable_sleep(e.rate_limit.reset_in) { stop? }
|
100
138
|
retry
|
101
139
|
rescue => e
|
102
|
-
@logger.warn("Twitter client error", :message => e.message, :exception => e, :backtrace => e.backtrace)
|
140
|
+
@logger.warn("Twitter client error", :message => e.message, :exception => e, :backtrace => e.backtrace, :options => @filter_options)
|
103
141
|
retry
|
104
142
|
end
|
105
143
|
end # def run
|
106
144
|
|
145
|
+
def stop
|
146
|
+
@stream_client = nil
|
147
|
+
end
|
148
|
+
|
149
|
+
def twitter_options
|
150
|
+
@twitter_options
|
151
|
+
end
|
152
|
+
|
153
|
+
def set_stream_client(client)
|
154
|
+
@stream_client = client
|
155
|
+
end
|
156
|
+
|
107
157
|
private
|
158
|
+
|
159
|
+
def tweet_processor(queue, tweet)
|
160
|
+
if tweet.is_a?(Twitter::Tweet)
|
161
|
+
return if ignore?(tweet)
|
162
|
+
event = from_tweet(tweet)
|
163
|
+
decorate(event)
|
164
|
+
queue << event
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def ignore?(tweet)
|
169
|
+
@ignore_retweets && tweet.retweet?
|
170
|
+
end
|
171
|
+
|
108
172
|
def from_tweet(tweet)
|
109
173
|
@logger.debug? && @logger.debug("Got tweet", :user => tweet.user.screen_name, :text => tweet.text)
|
110
174
|
if @full_tweet
|
111
175
|
event = LogStash::Event.new(LogStash::Util.stringify_symbols(tweet.to_hash))
|
112
176
|
event.timestamp = LogStash::Timestamp.new(tweet.created_at)
|
113
177
|
else
|
114
|
-
|
178
|
+
|
179
|
+
attributes = {
|
115
180
|
LogStash::Event::TIMESTAMP => LogStash::Timestamp.new(tweet.created_at),
|
116
181
|
"message" => tweet.full_text,
|
117
182
|
"user" => tweet.user.screen_name,
|
118
183
|
"client" => tweet.source,
|
119
184
|
"retweeted" => tweet.retweeted?,
|
120
185
|
"source" => "http://twitter.com/#{tweet.user.screen_name}/status/#{tweet.id}"
|
121
|
-
|
186
|
+
}
|
187
|
+
|
188
|
+
attributes["hashtags"] = tweet.hashtags
|
189
|
+
attributes["symbols"] = tweet.symbols
|
190
|
+
attributes["user_mentions"] = tweet.user_mentions
|
191
|
+
|
192
|
+
event = LogStash::Event.new(attributes)
|
122
193
|
event["in-reply-to"] = tweet.in_reply_to_status_id if tweet.reply?
|
123
194
|
unless tweet.urls.empty?
|
124
195
|
event["urls"] = tweet.urls.map(&:expanded_url).map(&:to_s)
|
@@ -130,4 +201,33 @@ class LogStash::Inputs::Twitter < LogStash::Inputs::Base
|
|
130
201
|
|
131
202
|
event
|
132
203
|
end
|
204
|
+
|
205
|
+
def configure(c)
|
206
|
+
c.consumer_key = @consumer_key
|
207
|
+
c.consumer_secret = @consumer_secret.value
|
208
|
+
c.access_token = @oauth_token
|
209
|
+
c.access_token_secret = @oauth_token_secret.value
|
210
|
+
end
|
211
|
+
|
212
|
+
def build_options
|
213
|
+
build_options = {}
|
214
|
+
build_options[:track] = @keywords.join(",") if @keywords && !@keywords.empty?
|
215
|
+
build_options[:locations] = @locations if @locations && !@locations.empty?
|
216
|
+
build_options[:language] = @languages.join(",") if @languages && !@languages.empty?
|
217
|
+
|
218
|
+
if @follows && @follows.length > 0
|
219
|
+
build_options[:follow] = @follows.map do |username|
|
220
|
+
( !is_number?(username) ? find_user(username) : username )
|
221
|
+
end.join(",")
|
222
|
+
end
|
223
|
+
build_options
|
224
|
+
end
|
225
|
+
|
226
|
+
def find_user(username)
|
227
|
+
@rest_client.user(:user => username)
|
228
|
+
end
|
229
|
+
|
230
|
+
def is_number?(string)
|
231
|
+
/^(\d+)$/.match(string) ? true : false
|
232
|
+
end
|
133
233
|
end # class LogStash::Inputs::Twitter
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
|
3
3
|
s.name = 'logstash-input-twitter'
|
4
|
-
s.version = '2.0
|
4
|
+
s.version = '2.1.0'
|
5
5
|
s.licenses = ['Apache License (2.0)']
|
6
6
|
s.summary = "Read events from the twitter streaming api."
|
7
7
|
s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
|
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
|
22
22
|
# Gem dependencies
|
23
23
|
s.add_runtime_dependency "logstash-core", ">= 2.0.0.beta2", "< 3.0.0"
|
24
|
-
s.add_runtime_dependency 'twitter',
|
24
|
+
s.add_runtime_dependency 'twitter', '5.14.0'
|
25
25
|
s.add_runtime_dependency 'stud', '>= 0.0.22', '< 0.1'
|
26
26
|
|
27
27
|
s.add_development_dependency 'logstash-devutils'
|
data/spec/inputs/twitter_spec.rb
CHANGED
@@ -1,29 +1,193 @@
|
|
1
|
-
|
2
|
-
require 'logstash/inputs/twitter'
|
3
|
-
require 'twitter'
|
1
|
+
require_relative "../spec_helper"
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
describe LogStash::Inputs::Twitter do
|
4
|
+
|
5
|
+
let(:config) do
|
6
|
+
{
|
7
|
+
'consumer_key' => 'foo',
|
8
|
+
'consumer_secret' => 'foo',
|
9
|
+
'oauth_token' => 'foo',
|
10
|
+
'oauth_token_secret' => 'foo',
|
11
|
+
'keywords' => ['foo', 'bar']
|
12
|
+
}
|
8
13
|
end
|
9
|
-
end
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
|
15
|
+
let(:plugin) { LogStash::Inputs::Twitter.new(config) }
|
16
|
+
|
17
|
+
describe "registration" do
|
18
|
+
|
19
|
+
it "not raise error" do
|
20
|
+
expect {plugin.register}.to_not raise_error
|
21
|
+
end
|
22
|
+
|
23
|
+
context "with no required configuration fields" do
|
24
|
+
let(:config) do
|
25
|
+
{
|
26
|
+
'consumer_key' => 'foo',
|
27
|
+
'consumer_secret' => 'foo',
|
28
|
+
'oauth_token' => 'foo',
|
29
|
+
'oauth_token_secret' => 'foo',
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
it "raise an error if no required fields are specified" do
|
34
|
+
expect {plugin.register}.to raise_error(LogStash::ConfigurationError)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "when told to shutdown" do
|
40
|
+
before(:each) do
|
14
41
|
allow(Twitter::Streaming::Client).to receive(:new).and_return(MockClient.new)
|
15
42
|
end
|
43
|
+
it_behaves_like "an interruptible input plugin"
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "fetching from sample" do
|
47
|
+
|
48
|
+
let(:input) { LogStash::Inputs::Twitter.new(config) }
|
49
|
+
let(:queue) { Queue.new }
|
50
|
+
|
51
|
+
let(:config) do
|
52
|
+
{
|
53
|
+
'consumer_key' => 'foo',
|
54
|
+
'consumer_secret' => 'foo',
|
55
|
+
'oauth_token' => 'foo',
|
56
|
+
'oauth_token_secret' => 'foo',
|
57
|
+
'use_samples' => true
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
let(:stream_client) { double("stream-client") }
|
62
|
+
|
63
|
+
before(:each) do
|
64
|
+
input.register
|
65
|
+
input.set_stream_client(stream_client)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "uses the sample endpoint" do
|
69
|
+
expect(stream_client).to receive(:sample).once
|
70
|
+
run_input_with(input, queue)
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "stream filter" do
|
76
|
+
|
77
|
+
describe "options parsing" do
|
78
|
+
|
79
|
+
let(:plugin) { LogStash::Inputs::Twitter.new(config) }
|
16
80
|
|
17
|
-
it_behaves_like "an interruptible input plugin" do
|
18
81
|
let(:config) do
|
19
82
|
{
|
20
83
|
'consumer_key' => 'foo',
|
21
84
|
'consumer_secret' => 'foo',
|
22
85
|
'oauth_token' => 'foo',
|
23
86
|
'oauth_token_secret' => 'foo',
|
24
|
-
'keywords' => ['foo',
|
87
|
+
'keywords' => ['foo'],
|
88
|
+
'languages' => ['en', 'fr'],
|
89
|
+
'locations' => "1234,2343",
|
90
|
+
'follows' => [ '1234', '4321' ]
|
25
91
|
}
|
26
92
|
end
|
93
|
+
|
94
|
+
before(:each) do
|
95
|
+
plugin.register
|
96
|
+
end
|
97
|
+
|
98
|
+
let(:options) { plugin.twitter_options }
|
99
|
+
|
100
|
+
it "include the track filter in options" do
|
101
|
+
expect(options).to include(:track=>"foo")
|
102
|
+
end
|
103
|
+
|
104
|
+
it "include the language filter in options" do
|
105
|
+
expect(options).to include(:language=>"en,fr")
|
106
|
+
end
|
107
|
+
|
108
|
+
it "include the locations filter in options" do
|
109
|
+
expect(options).to include(:locations=>"1234,2343")
|
110
|
+
end
|
111
|
+
|
112
|
+
it "include the follows filter in options" do
|
113
|
+
expect(options).to include(:follow=>"1234,4321")
|
114
|
+
end
|
27
115
|
end
|
116
|
+
|
117
|
+
describe "run" do
|
118
|
+
|
119
|
+
let(:input) { LogStash::Inputs::Twitter.new(config) }
|
120
|
+
|
121
|
+
let(:queue) { Queue.new }
|
122
|
+
|
123
|
+
let(:stream_client) { double("stream-client") }
|
124
|
+
|
125
|
+
let(:options) do
|
126
|
+
{:track=>"foo,bar"}
|
127
|
+
end
|
128
|
+
|
129
|
+
before(:each) do
|
130
|
+
input.register
|
131
|
+
input.set_stream_client(stream_client)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "using the filter endpoint" do
|
135
|
+
expect(stream_client).to receive(:filter).with(options).once
|
136
|
+
run_input_with(input, queue)
|
137
|
+
end
|
138
|
+
|
139
|
+
context "when not filtering retweets" do
|
140
|
+
|
141
|
+
let(:tweet) { Twitter::Tweet.new(id: 1) }
|
142
|
+
|
143
|
+
let(:config) do
|
144
|
+
{
|
145
|
+
'consumer_key' => 'foo',
|
146
|
+
'consumer_secret' => 'foo',
|
147
|
+
'oauth_token' => 'foo',
|
148
|
+
'oauth_token_secret' => 'foo',
|
149
|
+
'keywords' => ['foo'],
|
150
|
+
'languages' => ['en', 'fr'],
|
151
|
+
'locations' => "1234,2343",
|
152
|
+
'ignore_retweets' => false
|
153
|
+
}
|
154
|
+
end
|
155
|
+
|
156
|
+
it "not exclude retweets" do
|
157
|
+
allow(tweet).to receive(:retweet?).and_return(true)
|
158
|
+
expect(input).to receive(:from_tweet).with(tweet)
|
159
|
+
expect(stream_client).to receive(:filter).at_least(:once).and_yield(tweet)
|
160
|
+
expect(queue).to receive(:<<)
|
161
|
+
run_input_with(input, queue)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context "when filtering retweets" do
|
166
|
+
|
167
|
+
let(:tweet) { Twitter::Tweet.new(id: 1) }
|
168
|
+
|
169
|
+
let(:config) do
|
170
|
+
{
|
171
|
+
'consumer_key' => 'foo',
|
172
|
+
'consumer_secret' => 'foo',
|
173
|
+
'oauth_token' => 'foo',
|
174
|
+
'oauth_token_secret' => 'foo',
|
175
|
+
'keywords' => ['foo'],
|
176
|
+
'languages' => ['en', 'fr'],
|
177
|
+
'locations' => "1234,2343",
|
178
|
+
'ignore_retweets' => true
|
179
|
+
}
|
180
|
+
end
|
181
|
+
|
182
|
+
it "exclude retweets" do
|
183
|
+
allow(tweet).to receive(:retweet?).and_return(true)
|
184
|
+
expect(stream_client).to receive(:filter).at_least(:once).and_yield(tweet)
|
185
|
+
expect(queue).not_to receive(:<<)
|
186
|
+
run_input_with(input, queue)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
28
192
|
end
|
29
193
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require_relative "../spec_helper"
|
2
|
+
|
3
|
+
describe LogStash::Inputs::Twitter do
|
4
|
+
|
5
|
+
describe "#receive", :integration => true do
|
6
|
+
|
7
|
+
context "keyword search" do
|
8
|
+
let(:config) do
|
9
|
+
<<-CONFIG
|
10
|
+
input {
|
11
|
+
twitter {
|
12
|
+
consumer_key => '#{ENV['TWITTER_CONSUMER_KEY']}'
|
13
|
+
consumer_secret => '#{ENV['TWITTER_CONSUMER_SECRET']}'
|
14
|
+
oauth_token => '#{ENV['TWITTER_OAUTH_TOKEN']}'
|
15
|
+
oauth_token_secret => '#{ENV['TWITTER_OAUTH_TOKEN_SECRET']}'
|
16
|
+
keywords => [ 'Barcelona' ]
|
17
|
+
full_tweet => true
|
18
|
+
}
|
19
|
+
}
|
20
|
+
CONFIG
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:events) do
|
24
|
+
input(config) do |pipeline, queue|
|
25
|
+
3.times.collect { queue.pop }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "receive a list of events from the twitter stream" do
|
30
|
+
expect(events.count).to eq(3)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "pulling from sample" do
|
35
|
+
let(:config) do
|
36
|
+
<<-CONFIG
|
37
|
+
input {
|
38
|
+
twitter {
|
39
|
+
consumer_key => '#{ENV['TWITTER_CONSUMER_KEY']}'
|
40
|
+
consumer_secret => '#{ENV['TWITTER_CONSUMER_SECRET']}'
|
41
|
+
oauth_token => '#{ENV['TWITTER_OAUTH_TOKEN']}'
|
42
|
+
oauth_token_secret => '#{ENV['TWITTER_OAUTH_TOKEN_SECRET']}'
|
43
|
+
use_samples => true
|
44
|
+
}
|
45
|
+
}
|
46
|
+
CONFIG
|
47
|
+
end
|
48
|
+
|
49
|
+
let(:events) do
|
50
|
+
input(config) do |pipeline, queue|
|
51
|
+
3.times.collect { queue.pop }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
let(:event) { events.first }
|
56
|
+
|
57
|
+
it "receive a list of events from the twitter stream" do
|
58
|
+
expect(events.count).to eq(3)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "contains the hashtags" do
|
62
|
+
expect(event["hashtags"]).to be_truthy
|
63
|
+
end
|
64
|
+
|
65
|
+
it "contains the symbols" do
|
66
|
+
expect(event["symbols"]).to be_truthy
|
67
|
+
end
|
68
|
+
|
69
|
+
it "contains the user_mentions" do
|
70
|
+
expect(event["user_mentions"]).to be_truthy
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require "logstash/devutils/rspec/spec_helper"
|
2
|
+
require 'logstash/inputs/twitter'
|
3
|
+
require 'twitter'
|
4
|
+
|
5
|
+
class MockClient
|
6
|
+
def filter(options)
|
7
|
+
loop { yield }
|
8
|
+
end
|
9
|
+
|
10
|
+
alias_method :sample, :filter
|
11
|
+
end
|
12
|
+
|
13
|
+
def run_input_with(input, queue)
|
14
|
+
t = Thread.new(input, queue) do |_input, _queue|
|
15
|
+
_input.run(_queue)
|
16
|
+
end
|
17
|
+
sleep 0.1
|
18
|
+
t.kill
|
19
|
+
end
|
metadata
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-input-twitter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
|
14
|
+
name: logstash-core
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
15
16
|
requirements:
|
16
17
|
- - '>='
|
17
18
|
- !ruby/object:Gem::Version
|
@@ -19,10 +20,7 @@ dependencies:
|
|
19
20
|
- - <
|
20
21
|
- !ruby/object:Gem::Version
|
21
22
|
version: 3.0.0
|
22
|
-
|
23
|
-
prerelease: false
|
24
|
-
type: :runtime
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirement: !ruby/object:Gem::Requirement
|
26
24
|
requirements:
|
27
25
|
- - '>='
|
28
26
|
- !ruby/object:Gem::Version
|
@@ -30,21 +28,32 @@ dependencies:
|
|
30
28
|
- - <
|
31
29
|
- !ruby/object:Gem::Version
|
32
30
|
version: 3.0.0
|
31
|
+
prerelease: false
|
32
|
+
type: :runtime
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
|
+
name: twitter
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - '='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 5.14.0
|
34
40
|
requirement: !ruby/object:Gem::Requirement
|
35
41
|
requirements:
|
36
42
|
- - '='
|
37
43
|
- !ruby/object:Gem::Version
|
38
|
-
version: 5.
|
39
|
-
name: twitter
|
44
|
+
version: 5.14.0
|
40
45
|
prerelease: false
|
41
46
|
type: :runtime
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: stud
|
42
49
|
version_requirements: !ruby/object:Gem::Requirement
|
43
50
|
requirements:
|
44
|
-
- - '
|
51
|
+
- - '>='
|
45
52
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
47
|
-
-
|
53
|
+
version: 0.0.22
|
54
|
+
- - <
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0.1'
|
48
57
|
requirement: !ruby/object:Gem::Requirement
|
49
58
|
requirements:
|
50
59
|
- - '>='
|
@@ -53,60 +62,53 @@ dependencies:
|
|
53
62
|
- - <
|
54
63
|
- !ruby/object:Gem::Version
|
55
64
|
version: '0.1'
|
56
|
-
name: stud
|
57
65
|
prerelease: false
|
58
66
|
type: :runtime
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: logstash-devutils
|
59
69
|
version_requirements: !ruby/object:Gem::Requirement
|
60
70
|
requirements:
|
61
71
|
- - '>='
|
62
72
|
- !ruby/object:Gem::Version
|
63
|
-
version: 0
|
64
|
-
- - <
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
version: '0.1'
|
67
|
-
- !ruby/object:Gem::Dependency
|
73
|
+
version: '0'
|
68
74
|
requirement: !ruby/object:Gem::Requirement
|
69
75
|
requirements:
|
70
76
|
- - '>='
|
71
77
|
- !ruby/object:Gem::Version
|
72
78
|
version: '0'
|
73
|
-
name: logstash-devutils
|
74
79
|
prerelease: false
|
75
80
|
type: :development
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: logstash-codec-plain
|
76
83
|
version_requirements: !ruby/object:Gem::Requirement
|
77
84
|
requirements:
|
78
85
|
- - '>='
|
79
86
|
- !ruby/object:Gem::Version
|
80
87
|
version: '0'
|
81
|
-
- !ruby/object:Gem::Dependency
|
82
88
|
requirement: !ruby/object:Gem::Requirement
|
83
89
|
requirements:
|
84
90
|
- - '>='
|
85
91
|
- !ruby/object:Gem::Version
|
86
92
|
version: '0'
|
87
|
-
name: logstash-codec-plain
|
88
93
|
prerelease: false
|
89
94
|
type: :development
|
90
|
-
version_requirements: !ruby/object:Gem::Requirement
|
91
|
-
requirements:
|
92
|
-
- - '>='
|
93
|
-
- !ruby/object:Gem::Version
|
94
|
-
version: '0'
|
95
95
|
description: This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program
|
96
96
|
email: info@elastic.co
|
97
97
|
executables: []
|
98
98
|
extensions: []
|
99
99
|
extra_rdoc_files: []
|
100
100
|
files:
|
101
|
+
- lib/logstash/inputs/twitter.rb
|
102
|
+
- spec/spec_helper.rb
|
103
|
+
- spec/inputs/twitter_spec.rb
|
104
|
+
- spec/integration/twitter_spec.rb
|
105
|
+
- logstash-input-twitter.gemspec
|
101
106
|
- CHANGELOG.md
|
107
|
+
- README.md
|
102
108
|
- CONTRIBUTORS
|
103
109
|
- Gemfile
|
104
110
|
- LICENSE
|
105
111
|
- NOTICE.TXT
|
106
|
-
- README.md
|
107
|
-
- lib/logstash/inputs/twitter.rb
|
108
|
-
- logstash-input-twitter.gemspec
|
109
|
-
- spec/inputs/twitter_spec.rb
|
110
112
|
homepage: http://www.elastic.co/guide/en/logstash/current/index.html
|
111
113
|
licenses:
|
112
114
|
- Apache License (2.0)
|
@@ -129,9 +131,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
131
|
version: '0'
|
130
132
|
requirements: []
|
131
133
|
rubyforge_project:
|
132
|
-
rubygems_version: 2.
|
134
|
+
rubygems_version: 2.1.9
|
133
135
|
signing_key:
|
134
136
|
specification_version: 4
|
135
137
|
summary: Read events from the twitter streaming api.
|
136
138
|
test_files:
|
139
|
+
- spec/spec_helper.rb
|
137
140
|
- spec/inputs/twitter_spec.rb
|
141
|
+
- spec/integration/twitter_spec.rb
|