loggregator_emitter 2.0.0.pre → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -4,18 +4,18 @@
4
4
 
5
5
  This gem provides an API to emit messages to the loggregator agent from Ruby applications.
6
6
 
7
- Create an emitter object with the loggregator router host and port, and source type of the emitter.
7
+ Create an emitter object with the loggregator router host and port, a source name of the emitter, and a shared secret (for signing).
8
8
 
9
9
  Call emit() or emit_error() on this emitter with the application GUID and the message string.
10
10
 
11
- ### Valid source types are:
11
+ ##### A valid source name is any 3 character string. Some common component sources are:
12
12
 
13
- LogMessage::SourceType::CLOUD_CONTROLLER
14
- LogMessage::SourceType::ROUTER
15
- LogMessage::SourceType::UAA
16
- LogMessage::SourceType::DEA
17
- LogMessage::SourceType::WARDEN_CONTAINER
18
- LogMessage::SourceType::LOGGREGATOR
13
+ API (Cloud Controller)
14
+ RTR (Go Router)
15
+ UAA
16
+ DEA
17
+ APP (Warden container)
18
+ LGR (Loggregator)
19
19
 
20
20
  ### Setup
21
21
 
@@ -27,7 +27,7 @@ Call emit() or emit_error() on this emitter with the application GUID and the me
27
27
 
28
28
  require "loggregator_emitter"
29
29
 
30
- emitter = LoggregatorEmitter::Emitter.new("10.10.10.16:38452", LogMessage::SourceType::CLOUD_CONTROLLER)
30
+ emitter = LoggregatorEmitter::Emitter.new("10.10.10.16:38452", "API")
31
31
 
32
32
  app_guid = "a8977cb6-3365-4be1-907e-0c878b3a4c6b" # The GUID(UUID) for the user's application
33
33
 
@@ -35,6 +35,9 @@ Call emit() or emit_error() on this emitter with the application GUID and the me
35
35
 
36
36
  emitter.emit_error(app_guid,error_message) # Emits messages with a message type of ERR
37
37
 
38
+ ### Regenerating Protobuf library
39
+ protoc --beefcake_out lib/loggregator_messages -I lib/loggregator_messages lib/loggregator_messages/log_message.proto
40
+
38
41
  ### Versioning
39
42
 
40
43
  This gem is versioned using [semantic versioning](http://semver.org/).
@@ -5,14 +5,33 @@ module LoggregatorEmitter
5
5
  MAX_MESSAGE_BYTE_SIZE = (9 * 1024) - 512
6
6
  TRUNCATED_STRING = "TRUNCATED"
7
7
 
8
- def initialize(loggregator_server, source_type, source_id = nil, secret=nil)
9
- raise ArgumentError, "Must provide valid source type" unless valid_source_type?(source_type)
10
-
8
+ SOURCE_TYPE_BY_ID = {
9
+ 1 => "CLOUD_CONTROLLER",
10
+ 2 => "ROUTER",
11
+ 3 => "UAA",
12
+ 4 => "DEA",
13
+ 5 => "WARDEN_CONTAINER",
14
+ 6 => "LOGGREGATOR",
15
+ }
16
+
17
+ def initialize(loggregator_server, source_type_or_name, source_id = nil, secret=nil)
11
18
  @host, @port = loggregator_server.split(/:([^:]*$)/)
12
19
  raise ArgumentError, "Must provide valid loggregator server: #{loggregator_server}" if !valid_hostname || !valid_port
20
+ raise ArgumentError, "Must provide valid source_type_or_name: #{source_type_or_name}" unless source_type_or_name
21
+
22
+ case source_type_or_name
23
+ when LogMessage::SourceType::CLOUD_CONTROLLER..LogMessage::SourceType::LOGGREGATOR
24
+ @source_type = source_type_or_name
25
+ @source_name = SOURCE_TYPE_BY_ID[source_type_or_name]
26
+ when String
27
+ raise ArgumentError, "Custom Source String must be 3 characters" unless source_type_or_name.size == 3
28
+ @source_type = LogMessage::SourceType::UNKNOWN
29
+ @source_name = source_type_or_name
30
+ else
31
+ raise ArgumentError, "Invalid source: #{source_type_or_name.inspect} Please use a string or a known source type constant"
32
+ end
13
33
 
14
34
  @secret = secret
15
- @source_type = source_type
16
35
  @source_id = source_id && source_id.to_s
17
36
  end
18
37
 
@@ -34,10 +53,14 @@ module LoggregatorEmitter
34
53
  @host && !@host.match(/:\/\//)
35
54
  end
36
55
 
56
+ def split_message(message)
57
+ message.split(/\n|\r/).reject { |a| a.empty? }
58
+ end
59
+
37
60
  def emit_message(app_id, message, type)
38
61
  return unless app_id && message && message.strip.length > 0
39
62
 
40
- message.split(/\r\n|\n\r|\n|\r/).each do |m|
63
+ split_message(message).each do |m|
41
64
  if m.bytesize > MAX_MESSAGE_BYTE_SIZE
42
65
  m = m.byteslice(0, MAX_MESSAGE_BYTE_SIZE-TRUNCATED_STRING.bytesize) + TRUNCATED_STRING
43
66
  end
@@ -46,7 +69,7 @@ module LoggregatorEmitter
46
69
  send_protobuffer(create_log_message(app_id, m, type))
47
70
  else
48
71
  send_protobuffer(create_log_envelope(app_id, m, type))
49
- end
72
+ end
50
73
  end
51
74
  end
52
75
 
@@ -57,6 +80,7 @@ module LoggregatorEmitter
57
80
  lm.app_id = app_id
58
81
  lm.source_id = @source_id
59
82
  lm.source_type = @source_type
83
+ lm.source_name = @source_name
60
84
  lm.message_type = type
61
85
  lm
62
86
  end
@@ -80,14 +104,5 @@ module LoggregatorEmitter
80
104
  s.do_not_reverse_lookup = true
81
105
  s.sendmsg_nonblock(result, 0, addrinfo_udp)
82
106
  end
83
-
84
- def valid_source_type?(source_type)
85
- LogMessage::SourceType.constants.each do |name|
86
- if LogMessage::SourceType.const_get(name) == source_type
87
- return true
88
- end
89
- end
90
- false
91
- end
92
107
  end
93
108
  end
@@ -16,6 +16,7 @@ class LogMessage
16
16
  DEA = 4
17
17
  WARDEN_CONTAINER = 5
18
18
  LOGGREGATOR = 6
19
+ UNKNOWN = 7
19
20
  end
20
21
 
21
22
  required :message, :bytes, 1
@@ -25,6 +26,7 @@ class LogMessage
25
26
  required :source_type, LogMessage::SourceType, 5
26
27
  optional :source_id, :string, 6
27
28
  repeated :drain_urls, :string, 7
29
+ optional :source_name, :string, 8
28
30
 
29
31
  end
30
32
 
@@ -13,6 +13,7 @@ message LogMessage {
13
13
  DEA = 4;
14
14
  WARDEN_CONTAINER = 5;
15
15
  LOGGREGATOR = 6;
16
+ UNKNOWN = 7;
16
17
  }
17
18
 
18
19
  required bytes message = 1;
@@ -22,6 +23,7 @@ message LogMessage {
22
23
  required SourceType source_type = 5;
23
24
  optional string source_id = 6;
24
25
  repeated string drain_urls = 7;
26
+ optional string source_name = 8;
25
27
  }
26
28
 
27
29
  message LogEnvelope {
@@ -3,14 +3,6 @@ class LogMessage
3
3
  {MessageType::OUT => 'STDOUT', MessageType::ERR => 'STDERR'}[message_type]
4
4
  end
5
5
 
6
- def source_type_name
7
- {SourceType::CLOUD_CONTROLLER => 'CF[CC]',
8
- SourceType::ROUTER => 'CF[Router]',
9
- SourceType::UAA => 'CF[UAA]',
10
- SourceType::DEA => 'CF[DEA]',
11
- SourceType::WARDEN_CONTAINER => 'App',}[source_type]
12
- end
13
-
14
6
  def time=(time)
15
7
  self.timestamp = (time.tv_sec * 1000000000) + time.tv_nsec
16
8
  end
@@ -1,3 +1,4 @@
1
+ # coding: US-ASCII
1
2
  require 'digest/sha1'
2
3
  require 'openssl'
3
4
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "loggregator_emitter"
5
- spec.version = '2.0.0.pre'
5
+ spec.version = '2.0.0'
6
6
  spec.authors = ["Pivotal"]
7
7
  spec.email = ["cf-eng@pivotallabs.com"]
8
8
  spec.description = "Library to emit data to Loggregator"
@@ -0,0 +1,65 @@
1
+ require "support/fake_loggregator_server"
2
+ require "loggregator_emitter"
3
+
4
+ class MessageFixture
5
+ attr_reader :name, :message
6
+
7
+ def initialize(name, message, server_threshold, no_server_threshold)
8
+ @name = name
9
+ @message = message
10
+ @server_threshold = server_threshold
11
+ @no_server_threshold = no_server_threshold
12
+ end
13
+
14
+ def expected(using_server)
15
+ using_server ? @server_threshold : @no_server_threshold
16
+ end
17
+ end
18
+
19
+ class FreePort
20
+ def self.next_free_port
21
+ @@next_free_port ||= 12345
22
+ @@next_free_port += 1
23
+ end
24
+ end
25
+
26
+ shared_examples "a performance test" do |fixture, using_server|
27
+ let(:free_port) { FreePort.next_free_port }
28
+ let(:iterations) { using_server ? 100 : 1000 }
29
+ subject(:emitter) { LoggregatorEmitter::Emitter.new("localhost:#{free_port}", "API", 42, "my-secret") }
30
+
31
+ before do
32
+ if using_server
33
+ @server = FakeLoggregatorServer.new(free_port)
34
+ @server.start
35
+ else
36
+ emitter.should_receive(:send_protobuffer).at_least(iterations).times
37
+ end
38
+ end
39
+
40
+ after do
41
+ @server.stop if using_server
42
+ end
43
+
44
+ it "emits #{fixture.name} within a time threshold #{using_server ? 'with' : 'without'} server" do
45
+ start_time = Time.now.to_f
46
+
47
+ iterations.times { emitter.emit("my_app_id", fixture.message) }
48
+
49
+ expect(Time.now.to_f - start_time).to be < fixture.expected(using_server)
50
+ end
51
+
52
+ end
53
+
54
+ describe LoggregatorEmitter do
55
+ @fixtures = []
56
+ @fixtures << MessageFixture.new("long_message", (124*1024).times.collect { "a" }.join(""), 2.0, 2.0)
57
+ @fixtures << MessageFixture.new("message with newlines", 10.times.collect { (6*1024).times.collect { "a" }.join("") + "\n" }.join(""), 3.0, 3.0)
58
+ @fixtures << MessageFixture.new("message worst case", (124*1024).times.collect { "a" }.join("") + "\n", 2.0, 2.0)
59
+
60
+ [true, false].each do |using_server|
61
+ @fixtures.each do |fixture|
62
+ it_behaves_like "a performance test", fixture, using_server
63
+ end
64
+ end
65
+ end
@@ -25,6 +25,10 @@ describe LoggregatorEmitter do
25
25
  it "is valid if a server name is given" do
26
26
  expect { LoggregatorEmitter::Emitter.new("some-unknown-address:12345", LogMessage::SourceType::DEA) }.not_to raise_error
27
27
  end
28
+
29
+ it "accepts a string as source type/name" do
30
+ expect { LoggregatorEmitter::Emitter.new("some-unknown-address:12345", "STG") }.not_to raise_error
31
+ end
28
32
  end
29
33
 
30
34
  describe "invalid configurations" do
@@ -32,11 +36,22 @@ describe LoggregatorEmitter do
32
36
  it "raises if host has protocol" do
33
37
  expect { LoggregatorEmitter::Emitter.new("http://0.0.0.0:12345", LogMessage::SourceType::DEA) }.to raise_error(ArgumentError)
34
38
  end
35
- end
36
39
 
37
- describe "error based on source_type" do
38
- it "raises if source_type is invalid" do
39
- expect { LoggregatorEmitter::Emitter.new("0.0.0.0:12345", 40) }.to raise_error(ArgumentError)
40
+ it "raises if source is an unknown integer" do
41
+ expect { LoggregatorEmitter::Emitter.new("some-unknown-address:12345", 7) }.to raise_error(ArgumentError)
42
+ end
43
+
44
+ it "raises if source is not an integer or string" do
45
+ expect { LoggregatorEmitter::Emitter.new("some-unknown-address:12345", nil) }.to raise_error(ArgumentError)
46
+ expect { LoggregatorEmitter::Emitter.new("some-unknown-address:12345", 12.0) }.to raise_error(ArgumentError)
47
+ end
48
+
49
+ it "raises if source is too large of a string" do
50
+ expect { LoggregatorEmitter::Emitter.new("some-unknown-address:12345", "ABCD") }.to raise_error(ArgumentError)
51
+ end
52
+
53
+ it "raises if source is too small of a string" do
54
+ expect { LoggregatorEmitter::Emitter.new("some-unknown-address:12345", "AB") }.to raise_error(ArgumentError)
40
55
  end
41
56
  end
42
57
  end
@@ -192,7 +207,7 @@ describe LoggregatorEmitter do
192
207
  end
193
208
  end
194
209
 
195
- describe "source id" do
210
+ describe "source" do
196
211
  before do
197
212
  @server = FakeLoggregatorServer.new(free_port)
198
213
  @server.start
@@ -210,17 +225,28 @@ describe LoggregatorEmitter do
210
225
  @server.messages[0]
211
226
  end
212
227
 
213
- it "can be nil" do
228
+ it "when type is known" do
229
+ @emitter = LoggregatorEmitter::Emitter.new("0.0.0.0:#{free_port}", LogMessage::SourceType::CLOUD_CONTROLLER)
230
+ expect(emit_message.source_name).to eq "CLOUD_CONTROLLER"
231
+ end
232
+
233
+ it "when type is unknown" do
234
+ @emitter = LoggregatorEmitter::Emitter.new("0.0.0.0:#{free_port}", "STG")
235
+ expect(emit_message.source_name).to eq "STG"
236
+ expect(emit_message.source_type).to eq LogMessage::SourceType::UNKNOWN
237
+ end
238
+
239
+ it "id can be nil" do
214
240
  @emitter = LoggregatorEmitter::Emitter.new("0.0.0.0:#{free_port}", LogMessage::SourceType::CLOUD_CONTROLLER)
215
241
  expect(emit_message.source_id).to eq nil
216
242
  end
217
243
 
218
- it "can be passed in as a string" do
244
+ it "id can be passed in as a string" do
219
245
  @emitter = LoggregatorEmitter::Emitter.new("0.0.0.0:#{free_port}", LogMessage::SourceType::CLOUD_CONTROLLER, "some_source_id")
220
246
  expect(emit_message.source_id).to eq "some_source_id"
221
247
  end
222
248
 
223
- it "can be passed in as an integer" do
249
+ it "id can be passed in as an integer" do
224
250
  @emitter = LoggregatorEmitter::Emitter.new("0.0.0.0:#{free_port}", LogMessage::SourceType::CLOUD_CONTROLLER, 13)
225
251
  expect(emit_message.source_id).to eq "13"
226
252
  end
@@ -9,7 +9,7 @@ describe LogMessage do
9
9
  :message => "thesearebytes",
10
10
  :message_type => 1,
11
11
  :timestamp => 3,
12
- :source_type => 3
12
+ :source_type => "UAA"
13
13
  })
14
14
 
15
15
  expect(msg.message_type_name).to eq("STDOUT")
@@ -21,72 +21,13 @@ describe LogMessage do
21
21
  :message => "thesearebytes",
22
22
  :message_type => 2,
23
23
  :timestamp => 3,
24
- :source_type => 3
24
+ :source_type => "UAA"
25
25
  })
26
26
 
27
27
  expect(msg.message_type_name).to eq("STDERR")
28
28
  end
29
29
  end
30
30
 
31
- describe "#source_type_name" do
32
- it "returns CloudController for type == 1" do
33
- msg = LogMessage.new(
34
- {
35
- :message => "thesearebytes",
36
- :message_type => 1,
37
- :timestamp => 3,
38
- :source_type => 1
39
- })
40
-
41
- expect(msg.source_type_name).to eq("CF[CC]")
42
- end
43
-
44
- it "returns Router for type == 2" do
45
- msg = LogMessage.new(
46
- {
47
- :message => "thesearebytes",
48
- :message_type => 2,
49
- :timestamp => 3,
50
- :source_type => 2
51
- })
52
-
53
- expect(msg.source_type_name).to eq("CF[Router]")
54
- end
55
- it "returns UAA for type == 3" do
56
- msg = LogMessage.new(
57
- {
58
- :message => "thesearebytes",
59
- :message_type => 2,
60
- :timestamp => 3,
61
- :source_type => 3
62
- })
63
-
64
- expect(msg.source_type_name).to eq("CF[UAA]")
65
- end
66
- it "returns DEA for type == 4" do
67
- msg = LogMessage.new(
68
- {
69
- :message => "thesearebytes",
70
- :message_type => 2,
71
- :timestamp => 3,
72
- :source_type => 4
73
- })
74
-
75
- expect(msg.source_type_name).to eq("CF[DEA]")
76
- end
77
- it "returns WardenContainer for type == 5" do
78
- msg = LogMessage.new(
79
- {
80
- :message => "thesearebytes",
81
- :message_type => 2,
82
- :timestamp => 3,
83
- :source_type => 5
84
- })
85
-
86
- expect(msg.source_type_name).to eq("App")
87
- end
88
- end
89
-
90
31
  describe "#time=" do
91
32
  it "takes a time object" do
92
33
  msg = LogMessage.new
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loggregator_emitter
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.pre
5
- prerelease: 6
4
+ version: 2.0.0
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Pivotal
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-10-29 00:00:00.000000000 Z
12
+ date: 2013-11-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: beefcake
@@ -95,6 +95,7 @@ files:
95
95
  - lib/loggregator_messages/log_message_extender.rb
96
96
  - lib/symmetric/encryption.rb
97
97
  - loggregator_emitter.gemspec
98
+ - spec/loggregator_emitter/emit_performance_spec.rb
98
99
  - spec/loggregator_emitter/emit_spec.rb
99
100
  - spec/loggregator_emitter/encryption_spec.rb
100
101
  - spec/loggregator_emitter/log_message_extender_spec.rb
@@ -115,9 +116,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
115
116
  required_rubygems_version: !ruby/object:Gem::Requirement
116
117
  none: false
117
118
  requirements:
118
- - - ! '>'
119
+ - - ! '>='
119
120
  - !ruby/object:Gem::Version
120
- version: 1.3.1
121
+ version: '0'
122
+ segments:
123
+ - 0
124
+ hash: 584721548114788876
121
125
  requirements: []
122
126
  rubyforge_project:
123
127
  rubygems_version: 1.8.25
@@ -125,6 +129,7 @@ signing_key:
125
129
  specification_version: 3
126
130
  summary: Library to emit data to Loggregator
127
131
  test_files:
132
+ - spec/loggregator_emitter/emit_performance_spec.rb
128
133
  - spec/loggregator_emitter/emit_spec.rb
129
134
  - spec/loggregator_emitter/encryption_spec.rb
130
135
  - spec/loggregator_emitter/log_message_extender_spec.rb