logplex 0.0.1.pre.4 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +7 -5
- data/.travis.yml +5 -0
- data/README.md +5 -4
- data/lib/logplex/configuration.rb +3 -2
- data/lib/logplex/message.rb +6 -6
- data/lib/logplex/publisher.rb +16 -17
- data/lib/logplex/version.rb +1 -1
- data/logplex.gemspec +3 -4
- data/spec/logplex/configuration_spec.rb +8 -6
- data/spec/logplex/message_spec.rb +8 -8
- data/spec/logplex/publisher_spec.rb +73 -70
- data/spec/spec_helper.rb +0 -2
- metadata +30 -37
- data/spec/support/fake_logplex.rb +0 -108
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c4893a14a5e951127278dc97ceae12d4393ffc38093aa1286cd60d461c359019
|
4
|
+
data.tar.gz: 9f00eb2d50069f359e0cda648d56275c4193328642329181242730542406dcb8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ead382824f30028f1e10ba9def8c85ecb1a53c99fbca875f4692d16b45773bb639d4ac6842eb22040b0f2de8652748147394e7e6a183fb7953f98a98314382c2
|
7
|
+
data.tar.gz: 4263bf12e586db1511bffe8ddf1c4533fd592bbe5cf68fbbd52c778c39378be1eebc45551ff4955a472090ec695a3135544272eadecbd89d6b0ebc1920766522
|
data/.gitignore
CHANGED
@@ -1,13 +1,14 @@
|
|
1
|
-
|
2
|
-
*.rbc
|
1
|
+
_yardoc
|
3
2
|
.bundle
|
4
3
|
.config
|
4
|
+
.ruby-version
|
5
5
|
.yardoc
|
6
|
-
|
7
|
-
|
8
|
-
_yardoc
|
6
|
+
*.gem
|
7
|
+
*.rbc
|
9
8
|
coverage
|
10
9
|
doc/
|
10
|
+
Gemfile.lock
|
11
|
+
InstalledFiles
|
11
12
|
lib/bundler/man
|
12
13
|
pkg
|
13
14
|
rdoc
|
@@ -15,3 +16,4 @@ spec/reports
|
|
15
16
|
test/tmp
|
16
17
|
test/version_tmp
|
17
18
|
tmp
|
19
|
+
.tags
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -8,7 +8,7 @@ Logplex is the Heroku log router, and can be found
|
|
8
8
|
### Publishing messages
|
9
9
|
|
10
10
|
```ruby
|
11
|
-
publisher = Logplex::Publisher.new(
|
11
|
+
publisher = Logplex::Publisher.new(logplex_url)
|
12
12
|
publisher.publish("There's a lady who's sure, all that glitters is gold",
|
13
13
|
process: 'worker.2', host: 'some-host')
|
14
14
|
```
|
@@ -31,7 +31,8 @@ eg: [log2viz](https://blog.heroku.com/archives/2013/3/19/log2viz)
|
|
31
31
|
publisher.publish { vocals: 'Robert Plant', guitar: 'Jimmy Page' }
|
32
32
|
# produces the message: vocals='Robert Plant' guitar='Jimmy Page'
|
33
33
|
```
|
34
|
-
|
34
|
+
|
35
|
+
### Consuming messages
|
35
36
|
|
36
37
|
TBD
|
37
38
|
|
@@ -41,7 +42,7 @@ You can configure default values for logplex message posting:
|
|
41
42
|
|
42
43
|
```ruby
|
43
44
|
Logplex.configure do |config|
|
44
|
-
config.logplex_url = 'https://logplex.example.com'
|
45
|
+
config.logplex_url = 'https://logplex.example.com/logs'
|
45
46
|
config.process = 'stats'
|
46
47
|
config.host = 'host'
|
47
48
|
config.publish_timeout = 2
|
@@ -52,7 +53,7 @@ In the example above, it is now not not necessary to specify a logplex URL,
|
|
52
53
|
process or host when getting a hold of a publisher and publishing messages:
|
53
54
|
|
54
55
|
```ruby
|
55
|
-
publisher = Logplex::Publisher.new
|
56
|
+
publisher = Logplex::Publisher.new
|
56
57
|
publisher.publish "And she's buying a stairway to heaven"
|
57
58
|
```
|
58
59
|
|
@@ -1,14 +1,16 @@
|
|
1
1
|
module Logplex
|
2
2
|
class Configuration
|
3
3
|
attr_accessor :logplex_url,
|
4
|
+
:app_name,
|
4
5
|
:process,
|
5
6
|
:host,
|
6
7
|
:publish_timeout
|
7
8
|
|
8
9
|
def initialize
|
9
|
-
@logplex_url = 'https://east.logplex.io'
|
10
|
+
@logplex_url = 'https://east.logplex.io/logs'
|
10
11
|
@host = 'localhost'
|
11
12
|
@publish_timeout = 1
|
13
|
+
@app_name = 'app'
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
@@ -20,5 +22,4 @@ module Logplex
|
|
20
22
|
self.configuration ||= Configuration.new
|
21
23
|
yield(configuration)
|
22
24
|
end
|
23
|
-
|
24
25
|
end
|
data/lib/logplex/message.rb
CHANGED
@@ -13,8 +13,8 @@ module Logplex
|
|
13
13
|
FIELD_DISABLED = '-'.freeze
|
14
14
|
|
15
15
|
def initialize(message, opts = {})
|
16
|
-
@message
|
17
|
-
@
|
16
|
+
@message = message
|
17
|
+
@app_name = opts[:app_name] || Logplex.configuration.app_name
|
18
18
|
@time = opts[:time] || DateTime.now
|
19
19
|
@process = opts[:process] || Logplex.configuration.process
|
20
20
|
@host = opts[:host] || Logplex.configuration.host
|
@@ -22,7 +22,7 @@ module Logplex
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def syslog_frame
|
25
|
-
temp = "#{FACILITY_AND_PRIORITY} #{formatted_time} #{@host} #{@
|
25
|
+
temp = "#{FACILITY_AND_PRIORITY} #{formatted_time} #{@host} #{@app_name} #{@process} #{@message_id} #{FIELD_DISABLED} #{formatted_message}"
|
26
26
|
length = temp.length
|
27
27
|
"#{length} #{temp}"
|
28
28
|
end
|
@@ -34,7 +34,8 @@ module Logplex
|
|
34
34
|
errors.add(:host, "can't be nil") if @host.nil?
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
private
|
38
|
+
|
38
39
|
def formatted_time
|
39
40
|
case @time.class
|
40
41
|
when String
|
@@ -45,7 +46,7 @@ module Logplex
|
|
45
46
|
end
|
46
47
|
|
47
48
|
def formatted_message
|
48
|
-
if @message.
|
49
|
+
if @message.is_a?(Hash)
|
49
50
|
@message.inject([]) do |res, (key, value)|
|
50
51
|
res << %{#{key}="#{value}"}
|
51
52
|
end.join(' ')
|
@@ -53,6 +54,5 @@ module Logplex
|
|
53
54
|
@message
|
54
55
|
end
|
55
56
|
end
|
56
|
-
|
57
57
|
end
|
58
58
|
end
|
data/lib/logplex/publisher.rb
CHANGED
@@ -1,18 +1,17 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
require '
|
3
|
-
require 'restclient'
|
2
|
+
require 'excon'
|
4
3
|
require 'logplex/message'
|
5
4
|
require 'timeout'
|
6
5
|
|
7
6
|
module Logplex
|
8
7
|
class Publisher
|
9
|
-
PUBLISH_ERRORS = [
|
10
|
-
|
8
|
+
PUBLISH_ERRORS = [Excon::Errors::InternalServerError,
|
9
|
+
Excon::Errors::Unauthorized,
|
11
10
|
Timeout::Error].freeze
|
12
11
|
|
13
|
-
def initialize(
|
14
|
-
@token = token
|
12
|
+
def initialize(logplex_url = nil)
|
15
13
|
@logplex_url = logplex_url || Logplex.configuration.logplex_url
|
14
|
+
@token = URI(@logplex_url).password || Logplex.configuration.app_name
|
16
15
|
end
|
17
16
|
|
18
17
|
def publish(messages, opts={})
|
@@ -20,12 +19,12 @@ module Logplex
|
|
20
19
|
unless messages.is_a? Array
|
21
20
|
message_list = [message_list]
|
22
21
|
end
|
23
|
-
message_list.map! { |m| Message.new(m,
|
22
|
+
message_list.map! { |m| Message.new(m, { app_name: @token }.merge(opts)) }
|
24
23
|
message_list.each(&:validate)
|
25
24
|
if message_list.inject(true) { |accum, m| m.valid? }
|
26
25
|
begin
|
27
|
-
Timeout
|
28
|
-
api_post(message_list.map(&:syslog_frame).join(''))
|
26
|
+
Timeout.timeout(Logplex.configuration.publish_timeout) do
|
27
|
+
api_post(message_list.map(&:syslog_frame).join(''), message_list.length)
|
29
28
|
true
|
30
29
|
end
|
31
30
|
rescue *PUBLISH_ERRORS
|
@@ -34,14 +33,14 @@ module Logplex
|
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
36
|
+
private
|
37
|
+
|
38
|
+
def api_post(message, number_messages)
|
39
|
+
Excon.post(@logplex_url, body: message, headers: {
|
40
|
+
"Content-Type" => 'application/logplex-1',
|
41
|
+
"Content-Length" => message.length,
|
42
|
+
"Logplex-Msg-Count" => number_messages
|
43
|
+
}, expects: [200, 204])
|
45
44
|
end
|
46
45
|
end
|
47
46
|
end
|
data/lib/logplex/version.rb
CHANGED
data/logplex.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |gem|
|
|
8
8
|
gem.version = Logplex::VERSION
|
9
9
|
gem.authors = ["Harold Giménez"]
|
10
10
|
gem.email = ["harold.gimenez@gmail.com"]
|
11
|
-
gem.description =
|
12
|
-
gem.summary =
|
11
|
+
gem.description = "Publish and Consume Logplex messages"
|
12
|
+
gem.summary = "Publish and Consume Logplex messages"
|
13
13
|
gem.homepage = "https://practiceovertheory.com"
|
14
14
|
|
15
15
|
gem.files = `git ls-files`.split($/)
|
@@ -17,7 +17,6 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
gem.add_dependency "valcro"
|
20
|
-
gem.add_dependency "
|
20
|
+
gem.add_dependency "excon"
|
21
21
|
gem.add_development_dependency "rspec"
|
22
|
-
gem.add_development_dependency "sham_rack"
|
23
22
|
end
|
@@ -1,12 +1,14 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'logplex/configuration'
|
3
3
|
|
4
|
-
describe Logplex::Configuration
|
5
|
-
|
6
|
-
|
4
|
+
describe Logplex::Configuration do
|
5
|
+
describe 'defaults' do
|
6
|
+
it 'defaults to the production heroku logplex url' do
|
7
|
+
Logplex.configure { |config| }
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
expect(
|
10
|
+
Logplex.configuration.logplex_url
|
11
|
+
).to eq('https://east.logplex.io/logs')
|
12
|
+
end
|
11
13
|
end
|
12
14
|
end
|
@@ -7,7 +7,7 @@ describe Logplex::Message do
|
|
7
7
|
it 'fills out fields of a syslog message' do
|
8
8
|
message = Logplex::Message.new(
|
9
9
|
'my message here',
|
10
|
-
|
10
|
+
app_name: 't.some-token',
|
11
11
|
time: DateTime.parse("1980-08-23 05:31 00:00"),
|
12
12
|
process: 'heroku-postgres',
|
13
13
|
host: 'some-host',
|
@@ -20,17 +20,17 @@ describe Logplex::Message do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
it 'is invalid for messages longer than 10240 bytes' do
|
23
|
-
short = Logplex::Message.new('a' * 10240,
|
23
|
+
short = Logplex::Message.new('a' * 10240, app_name: 'foo',
|
24
24
|
process: 'proc',
|
25
25
|
host: 'host')
|
26
|
-
long = Logplex::Message.new('a' * 10241,
|
26
|
+
long = Logplex::Message.new('a' * 10241, app_name: 'foo',
|
27
27
|
process: 'proc',
|
28
28
|
host: 'host')
|
29
29
|
short.validate
|
30
30
|
long.validate
|
31
31
|
|
32
|
-
expect(short.valid?).to
|
33
|
-
expect(long.valid?).to
|
32
|
+
expect(short.valid?).to be_truthy
|
33
|
+
expect(long.valid?).to be_falsey
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'is invalid with no process or host' do
|
@@ -39,10 +39,10 @@ describe Logplex::Message do
|
|
39
39
|
conf.process = nil
|
40
40
|
end
|
41
41
|
|
42
|
-
message = Logplex::Message.new("a message",
|
42
|
+
message = Logplex::Message.new("a message", app_name: 't.some-token')
|
43
43
|
message.validate
|
44
44
|
|
45
|
-
expect(message.valid?).to
|
45
|
+
expect(message.valid?).to be_falsey
|
46
46
|
expect(message.errors[:process]).to eq ["can't be nil"]
|
47
47
|
expect(message.errors[:host]).to eq ["can't be nil"]
|
48
48
|
end
|
@@ -50,7 +50,7 @@ describe Logplex::Message do
|
|
50
50
|
it 'formats logs as key/values when given a hash' do
|
51
51
|
message = Logplex::Message.new(
|
52
52
|
{ vocals: 'Robert Plant', guitar: 'Jimmy Page' },
|
53
|
-
|
53
|
+
app_name: 't.some-token',
|
54
54
|
process: 'proc',
|
55
55
|
host: 'host',
|
56
56
|
time: DateTime.parse("1980-08-23 05:31 00:00")
|
@@ -1,96 +1,99 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'sham_rack'
|
3
2
|
require 'logplex/publisher'
|
4
|
-
require '
|
3
|
+
require 'logplex/message'
|
5
4
|
|
6
|
-
describe Logplex::Publisher
|
7
|
-
|
8
|
-
Logplex.configure do |config|
|
9
|
-
config.process = "postgres"
|
10
|
-
config.host = "host"
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
context 'with a working logplex' do
|
5
|
+
describe Logplex::Publisher do
|
6
|
+
describe '#publish' do
|
15
7
|
before do
|
16
|
-
|
17
|
-
|
8
|
+
Excon.defaults[:mock] = true
|
9
|
+
Logplex.configure do |config|
|
10
|
+
config.process = "postgres"
|
11
|
+
config.host = "host"
|
12
|
+
end
|
18
13
|
end
|
19
14
|
|
20
15
|
after do
|
21
|
-
|
22
|
-
FakeLogplex.clear!
|
23
|
-
restore_default_config
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'encodes a message and publishes it' do
|
27
|
-
FakeLogplex.register_token('t.some-token')
|
28
|
-
|
29
|
-
message = 'I have a message for you'
|
30
|
-
publisher = Logplex::Publisher.new('t.some-token', 'https://logplex.example.com')
|
31
|
-
publisher.publish(message)
|
32
|
-
|
33
|
-
expect(FakeLogplex).to have_received_message(message)
|
16
|
+
Excon.stubs.clear
|
34
17
|
end
|
35
18
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
publisher = Logplex::Publisher.new('t.some-token', 'https://logplex.example.com')
|
41
|
-
|
42
|
-
publisher.publish(messages)
|
43
|
-
|
44
|
-
messages.each do |message|
|
45
|
-
expect(FakeLogplex).to have_received_message(message)
|
19
|
+
context 'with a working logplex' do
|
20
|
+
after do
|
21
|
+
restore_default_config
|
46
22
|
end
|
47
23
|
|
48
|
-
|
49
|
-
|
24
|
+
it 'encodes a message and publishes it' do
|
25
|
+
Excon.stub({ method: :post, password: "t.some-token", body: /message for you/ }, status: 204)
|
26
|
+
message = 'I have a message for you'
|
27
|
+
publisher = Logplex::Publisher.new('https://token:t.some-token@logplex.example.com')
|
28
|
+
publisher.publish(message)
|
29
|
+
end
|
50
30
|
|
51
|
-
|
52
|
-
|
31
|
+
it 'sends many messages in one request when passed an array' do
|
32
|
+
Excon.stub({ method: :post, password: "t.some-token", body: /message for you.+here is another.+some final thoughts/ }, status: 204)
|
33
|
+
messages = ['I have a message for you', 'here is another', 'some final thoughts']
|
34
|
+
publisher = Logplex::Publisher.new('https://token:t.some-token@logplex.example.com')
|
35
|
+
publisher.publish(messages)
|
36
|
+
end
|
53
37
|
|
54
|
-
|
55
|
-
|
56
|
-
|
38
|
+
it 'uses the token if app_name is not given' do
|
39
|
+
Excon.stub({ method: :post, password: "t.some-token", body: /t.some-token/ }, status: 204)
|
40
|
+
message = 'I have a message for you'
|
41
|
+
publisher = Logplex::Publisher.new('https://token:t.some-token@logplex.example.com')
|
42
|
+
publisher.publish(message)
|
43
|
+
end
|
57
44
|
|
58
|
-
|
59
|
-
|
45
|
+
it 'uses the given app_name' do
|
46
|
+
Excon.stub({ method: :post, password: "t.some-token", body: /foo/ }, status: 204)
|
47
|
+
message = 'I have a message for you'
|
48
|
+
publisher = Logplex::Publisher.new('https://token:t.some-token@logplex.example.com')
|
49
|
+
publisher.publish(message, app_name: 'foo')
|
50
|
+
end
|
60
51
|
|
61
|
-
|
62
|
-
|
52
|
+
it 'does the thing' do
|
53
|
+
Excon.stub({ method: :post, password: "t.some-token", body: /hi\="there\"/ }, status: 204)
|
54
|
+
message = { hi: 'there' }
|
55
|
+
publisher = Logplex::Publisher.new('https://token:t.some-token@logplex.example.com')
|
56
|
+
expect(publisher.publish(message)).to be_truthy
|
57
|
+
end
|
63
58
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
59
|
+
it 'returns true' do
|
60
|
+
Excon.stub({ method: :post, password: "t.some-token" }, status: 204)
|
61
|
+
message = 'I have a message for you'
|
62
|
+
publisher = Logplex::Publisher.new('https://token:t.some-token@logplex.example.com')
|
63
|
+
expect(publisher.publish(message)).to be_truthy
|
64
|
+
end
|
68
65
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
66
|
+
it "returns false when there's an auth error" do
|
67
|
+
Excon.stub({ method: :post, password: "t.some-token" }, status: 401)
|
68
|
+
message = 'I have a message for you'
|
69
|
+
publisher = Logplex::Publisher.new('https://token:t.some-token@logplex.example.com')
|
70
|
+
expect(publisher.publish(message)).to be_falsey
|
71
|
+
end
|
73
72
|
end
|
74
|
-
end
|
75
73
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
74
|
+
context 'when the logplex service is acting up' do
|
75
|
+
it 'returns false' do
|
76
|
+
Excon.stub({ method: :post, password: "t.some-token" }, status: 500)
|
77
|
+
publisher = Logplex::Publisher.new('https://token:t.some-token@logplex.example.com')
|
78
|
+
expect(publisher.publish('hi')).to be_falsey
|
80
79
|
end
|
81
80
|
end
|
82
81
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
publisher
|
87
|
-
expect(publisher.publish('hi')).to be_false
|
82
|
+
it "handles timeouts" do
|
83
|
+
expect(Excon).to receive(:post).and_raise(Timeout::Error)
|
84
|
+
publisher = Logplex::Publisher.new('https://token:t.some-token@logplex.example.com')
|
85
|
+
expect(publisher.publish('hi')).to be_falsey
|
88
86
|
end
|
89
|
-
end
|
90
87
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
88
|
+
it "includes the correct headers" do
|
89
|
+
message = 'hello-harold'
|
90
|
+
headers = {
|
91
|
+
"Content-Type" => 'application/logplex-1',
|
92
|
+
"Content-Length" => 79,
|
93
|
+
"Logplex-Msg-Count" => 1
|
94
|
+
}
|
95
|
+
expect(Excon).to receive(:post).with(any_args, hash_including(:headers => headers))
|
96
|
+
Logplex::Publisher.new('https://token:t.some-token@logplex.example.com').publish(message)
|
97
|
+
end
|
95
98
|
end
|
96
99
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,60 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logplex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease: 6
|
4
|
+
version: 0.0.4
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Harold Giménez
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2021-07-13 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: valcro
|
16
|
-
requirement:
|
17
|
-
none: false
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
|
-
version_requirements:
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
25
27
|
- !ruby/object:Gem::Dependency
|
26
|
-
name:
|
27
|
-
requirement:
|
28
|
-
none: false
|
28
|
+
name: excon
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
29
30
|
requirements:
|
30
|
-
- -
|
31
|
+
- - ">="
|
31
32
|
- !ruby/object:Gem::Version
|
32
33
|
version: '0'
|
33
34
|
type: :runtime
|
34
35
|
prerelease: false
|
35
|
-
version_requirements:
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
36
41
|
- !ruby/object:Gem::Dependency
|
37
42
|
name: rspec
|
38
|
-
requirement:
|
39
|
-
none: false
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
40
44
|
requirements:
|
41
|
-
- -
|
45
|
+
- - ">="
|
42
46
|
- !ruby/object:Gem::Version
|
43
47
|
version: '0'
|
44
48
|
type: :development
|
45
49
|
prerelease: false
|
46
|
-
version_requirements:
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: sham_rack
|
49
|
-
requirement: &70169923644580 !ruby/object:Gem::Requirement
|
50
|
-
none: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
-
type: :development
|
56
|
-
prerelease: false
|
57
|
-
version_requirements: *70169923644580
|
58
55
|
description: Publish and Consume Logplex messages
|
59
56
|
email:
|
60
57
|
- harold.gimenez@gmail.com
|
@@ -62,8 +59,9 @@ executables: []
|
|
62
59
|
extensions: []
|
63
60
|
extra_rdoc_files: []
|
64
61
|
files:
|
65
|
-
- .gitignore
|
66
|
-
- .rspec
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".travis.yml"
|
67
65
|
- Gemfile
|
68
66
|
- LICENSE
|
69
67
|
- LICENSE.txt
|
@@ -79,35 +77,30 @@ files:
|
|
79
77
|
- spec/logplex/message_spec.rb
|
80
78
|
- spec/logplex/publisher_spec.rb
|
81
79
|
- spec/spec_helper.rb
|
82
|
-
- spec/support/fake_logplex.rb
|
83
80
|
homepage: https://practiceovertheory.com
|
84
81
|
licenses: []
|
82
|
+
metadata: {}
|
85
83
|
post_install_message:
|
86
84
|
rdoc_options: []
|
87
85
|
require_paths:
|
88
86
|
- lib
|
89
87
|
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
-
none: false
|
91
88
|
requirements:
|
92
|
-
- -
|
89
|
+
- - ">="
|
93
90
|
- !ruby/object:Gem::Version
|
94
91
|
version: '0'
|
95
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
-
none: false
|
97
93
|
requirements:
|
98
|
-
- -
|
94
|
+
- - ">="
|
99
95
|
- !ruby/object:Gem::Version
|
100
|
-
version:
|
96
|
+
version: '0'
|
101
97
|
requirements: []
|
102
|
-
|
103
|
-
rubygems_version: 1.8.10
|
98
|
+
rubygems_version: 3.0.3
|
104
99
|
signing_key:
|
105
|
-
specification_version:
|
100
|
+
specification_version: 4
|
106
101
|
summary: Publish and Consume Logplex messages
|
107
102
|
test_files:
|
108
103
|
- spec/logplex/configuration_spec.rb
|
109
104
|
- spec/logplex/message_spec.rb
|
110
105
|
- spec/logplex/publisher_spec.rb
|
111
106
|
- spec/spec_helper.rb
|
112
|
-
- spec/support/fake_logplex.rb
|
113
|
-
has_rdoc:
|
@@ -1,108 +0,0 @@
|
|
1
|
-
class FakeLogplex
|
2
|
-
class Message
|
3
|
-
|
4
|
-
attr_reader :message, :token
|
5
|
-
|
6
|
-
def initialize(opts)
|
7
|
-
@message = opts[:message]
|
8
|
-
@token = opts[:token]
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.from_syslog(syslog_message)
|
12
|
-
messages = []
|
13
|
-
anchor = 0
|
14
|
-
until anchor >= syslog_message.length
|
15
|
-
new_anchor, opts = extract_syslog_field(syslog_message, anchor)
|
16
|
-
raise "same" if anchor == new_anchor
|
17
|
-
anchor = new_anchor
|
18
|
-
messages << new(opts)
|
19
|
-
end
|
20
|
-
messages
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.extract_syslog_field(syslog_message, anchor)
|
24
|
-
start = anchor
|
25
|
-
pos = start
|
26
|
-
pos, bytes = next_syslog_field(syslog_message, anchor, pos)
|
27
|
-
anchor = pos+1
|
28
|
-
pos, facility = next_syslog_field(syslog_message, anchor, pos)
|
29
|
-
anchor = pos+1
|
30
|
-
pos, time = next_syslog_field(syslog_message, anchor, pos)
|
31
|
-
anchor = pos+1
|
32
|
-
pos, host = next_syslog_field(syslog_message, anchor, pos)
|
33
|
-
anchor = pos+1
|
34
|
-
pos, token = next_syslog_field(syslog_message, anchor, pos)
|
35
|
-
anchor = pos+1
|
36
|
-
pos, process = next_syslog_field(syslog_message, anchor, pos)
|
37
|
-
anchor = pos+1
|
38
|
-
pos, message_id = next_syslog_field(syslog_message, anchor, pos)
|
39
|
-
anchor = pos+1
|
40
|
-
pos, unknown = next_syslog_field(syslog_message, anchor, pos)
|
41
|
-
anchor = pos+1
|
42
|
-
|
43
|
-
limit = start + bytes + bytes.to_s.length
|
44
|
-
message = syslog_message[anchor..limit]
|
45
|
-
|
46
|
-
[limit + 1, { message: message, token: token }]
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.next_syslog_field(message, anchor, pos)
|
50
|
-
until char = message[pos+=1] and char == ' '
|
51
|
-
field = message[anchor..pos].to_i
|
52
|
-
end
|
53
|
-
[pos, field]
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
@@tokens = []
|
58
|
-
@@received_messages = []
|
59
|
-
@@requests_received = 0
|
60
|
-
|
61
|
-
def call(env)
|
62
|
-
@@requests_received += 1
|
63
|
-
|
64
|
-
message = env['rack.input'].read
|
65
|
-
method = env['REQUEST_METHOD']
|
66
|
-
path = env['PATH_INFO']
|
67
|
-
content_type = env['CONTENT_TYPE']
|
68
|
-
content_length = env['CONTENT_LENGTH'].to_i
|
69
|
-
auth = env['HTTP_AUTHORIZATION']
|
70
|
-
|
71
|
-
_, auth_token = auth.split(' ')
|
72
|
-
user, pass = Base64.decode64(auth_token).split(':')
|
73
|
-
if @@tokens.include?(pass)
|
74
|
-
if (method == 'POST' &&
|
75
|
-
path == '/logs' &&
|
76
|
-
content_type == 'application/logplex-1' &&
|
77
|
-
content_length == message.length)
|
78
|
-
|
79
|
-
@@received_messages << Message.from_syslog(message)
|
80
|
-
@@received_messages.flatten!
|
81
|
-
[200, {}, []]
|
82
|
-
else
|
83
|
-
[404, {}, []]
|
84
|
-
end
|
85
|
-
else
|
86
|
-
[401, {}, []]
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def self.has_received_message?(message)
|
91
|
-
@@received_messages.map(&:message).include? message
|
92
|
-
end
|
93
|
-
|
94
|
-
def self.register_token(token)
|
95
|
-
@@tokens << token
|
96
|
-
end
|
97
|
-
|
98
|
-
def self.clear!
|
99
|
-
@@tokens = []
|
100
|
-
@@received_messages = []
|
101
|
-
@@requests_received = 0
|
102
|
-
end
|
103
|
-
|
104
|
-
def self.requests_received
|
105
|
-
@@requests_received
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|