loggregator_emitter 2.0.0.pre → 2.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.
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