logplex 0.0.1.pre.4 → 0.0.4
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 +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
|
-
|