logs-cf-plugin 0.0.23.pre
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 +15 -0
- data/README.md +49 -0
- data/lib/logs-cf-plugin/log_target.rb +46 -0
- data/lib/logs-cf-plugin/loggregator_client.rb +116 -0
- data/lib/logs-cf-plugin/message_writer.rb +5 -0
- data/lib/logs-cf-plugin/plugin.rb +54 -0
- data/vendor/log_message/log_message.pb.rb +32 -0
- data/vendor/log_message/log_message.proto +25 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
OTI0ZDYyMGIwNjE4YTMwZjhmYWFlMDNmOTg5NmFmZGMyM2E0MjhkYQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NGI4NDQxYTUxYmM3Njc3MTBkZDVmNGI2YzM2NGY3NDYwZjY2ZTMzNw==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NmYwNjE5NWE0MjRhMzBjZDBlYmVkM2FiZjg5OGMwYzZiNDE4ZjUxODQ1YTU0
|
10
|
+
NDBlZTNhM2RmNWMxYWRkZTBkZjU0YTllMTI5NTkzODc4YTY2ZjYyMTUzOGFm
|
11
|
+
YWQ0MTFjMmQyZjhhOGE4ZGRlMjE2OWQ0NWViMGY4MjYzNGZlMzE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MmUyMWRkNDc5ZTFhMGRiMDM5NmI1M2EzMDE4ZWMzZDc3NGYyZjc5MTJkMDkw
|
14
|
+
NzdiNDgzNjU5NmYxYzI2OTk0MmQ4N2M3NTEyMDIyZTgyNWExMjUyMmFkZDQx
|
15
|
+
ZWM5NGI2MTZjY2E1NmY2Mjg4ZjVhZDJiZWFkOGVmZDZmNGYxYmY=
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Logs-Cf-Plugin [](https://travis-ci.org/cloudfoundry/logs-cf-plugin)
|
2
|
+
|
3
|
+
Plugin to cf command to add streaming application logs.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'logs-cf-plugin'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install logs-cf-plugin
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
After installing you can run cf logs and see your application's logs stream to the console.
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
The Cloud Foundry team uses GitHub and accepts contributions via [pull request](https://help.github.com/articles/using-pull-requests)
|
26
|
+
|
27
|
+
Follow these steps to make a contribution to any of our open source repositories:
|
28
|
+
|
29
|
+
1. Complete our CLA Agreement for [individuals](http://www.cloudfoundry.org/individualcontribution.pdf) or [corporations](http://www.cloudfoundry.org/corpcontribution.pdf)
|
30
|
+
1. Set your name and email
|
31
|
+
|
32
|
+
git config --global user.name "Firstname Lastname"
|
33
|
+
git config --global user.email "your_email@youremail.com"
|
34
|
+
|
35
|
+
1. Fork the repo
|
36
|
+
1. Make your changes on a topic branch, commit, and push to github and open a pull request.
|
37
|
+
|
38
|
+
Once your commits are approved by Travis CI and reviewed by the core team, they will be merged.
|
39
|
+
|
40
|
+
#### Checkout
|
41
|
+
|
42
|
+
git clone git@github.com:cloudfoundry/logs-cf-plugin.git
|
43
|
+
cd logs-cf-plugin/
|
44
|
+
bundle
|
45
|
+
|
46
|
+
#### Running tests
|
47
|
+
|
48
|
+
rake
|
49
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module LogsCfPlugin
|
2
|
+
class LogTarget
|
3
|
+
def initialize(target_organization, target_space, ids)
|
4
|
+
raise ArgumentError, "Requires 3 ids" unless ids.size == 3
|
5
|
+
@target_organization = target_organization
|
6
|
+
@target_space = target_space
|
7
|
+
|
8
|
+
@org_id = ids[0]
|
9
|
+
@space_id = ids[1]
|
10
|
+
@app_id = ids[2]
|
11
|
+
end
|
12
|
+
|
13
|
+
def ambiguous?
|
14
|
+
@target_organization && @target_space
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid?
|
18
|
+
!!target
|
19
|
+
end
|
20
|
+
|
21
|
+
def query_params
|
22
|
+
case target
|
23
|
+
when :org
|
24
|
+
{org: @org_id}
|
25
|
+
when :space
|
26
|
+
{org: @org_id, space: @space_id}
|
27
|
+
when :app
|
28
|
+
{org: @org_id, space: @space_id, app: @app_id}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def target
|
35
|
+
return nil if ambiguous?
|
36
|
+
case
|
37
|
+
when @target_organization
|
38
|
+
:org
|
39
|
+
when @target_space
|
40
|
+
:space
|
41
|
+
when @app_id
|
42
|
+
:app
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'log_message/log_message.pb'
|
2
|
+
require 'faye/websocket'
|
3
|
+
require 'eventmachine'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module LogsCfPlugin
|
7
|
+
class LoggregatorClient
|
8
|
+
include CFoundry::TraceHelpers
|
9
|
+
|
10
|
+
def initialize(loggregator_host, user_token, output, trace)
|
11
|
+
@output = output
|
12
|
+
@loggregator_host = loggregator_host
|
13
|
+
@user_token = user_token
|
14
|
+
@trace = trace
|
15
|
+
end
|
16
|
+
|
17
|
+
def listen(query_params)
|
18
|
+
websocket_address = "wss://#{loggregator_host}:4443/tail/?#{hash_to_query(query_params)}"
|
19
|
+
output.puts "websocket_address: #{websocket_address}" if trace
|
20
|
+
|
21
|
+
EM.run {
|
22
|
+
ws = Faye::WebSocket::Client.new(websocket_address, nil, :headers => {"Origin" => "http://localhost", "Authorization" => user_token})
|
23
|
+
|
24
|
+
ws.on :open do |event|
|
25
|
+
output.puts("Connected to server.")
|
26
|
+
EventMachine.add_periodic_timer(keep_alive_interval) do
|
27
|
+
ws.send([42])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
ws.on :message do |event|
|
32
|
+
received_message = LogMessage.decode(event.data.pack("C*"))
|
33
|
+
MessageWriter.write(output, received_message)
|
34
|
+
end
|
35
|
+
|
36
|
+
ws.on :error do |event|
|
37
|
+
output.puts("Server error")
|
38
|
+
output.puts(event.data.inspect) if trace
|
39
|
+
end
|
40
|
+
|
41
|
+
ws.on :close do |event|
|
42
|
+
ws.close
|
43
|
+
output.puts("Server dropped connection...goodbye.")
|
44
|
+
EM.stop
|
45
|
+
ws = nil
|
46
|
+
end
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def dump_messages(query_params)
|
51
|
+
uri = URI.parse("https://#{loggregator_host}/dump/?#{hash_to_query(query_params)}")
|
52
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
53
|
+
http.use_ssl = true
|
54
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
55
|
+
|
56
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
57
|
+
request['Authorization'] = user_token
|
58
|
+
|
59
|
+
if trace
|
60
|
+
request_hash = {
|
61
|
+
:url => uri.request_uri,
|
62
|
+
:method => "GET",
|
63
|
+
:headers => sane_headers(request),
|
64
|
+
:body => ""
|
65
|
+
}
|
66
|
+
output.puts(request_trace(request_hash))
|
67
|
+
end
|
68
|
+
|
69
|
+
response = http.request(request)
|
70
|
+
|
71
|
+
return [] unless response.code == "200"
|
72
|
+
|
73
|
+
response_bytes = StringIO.new(response.body)
|
74
|
+
messages = []
|
75
|
+
while len = response_bytes.read(4)
|
76
|
+
len = len.unpack("N")[0] # 32-bit length, BigEndian stylie
|
77
|
+
record = response_bytes.read(len) # This returns a string even if len is 0.
|
78
|
+
msg = LogMessage.decode(record)
|
79
|
+
messages << msg
|
80
|
+
end
|
81
|
+
|
82
|
+
if trace
|
83
|
+
response_hash = {
|
84
|
+
:headers => sane_headers(response),
|
85
|
+
:status => response.code,
|
86
|
+
:body => messages
|
87
|
+
}
|
88
|
+
output.puts(response_trace(response_hash))
|
89
|
+
end
|
90
|
+
|
91
|
+
messages
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def sane_headers(obj)
|
97
|
+
hds = {}
|
98
|
+
|
99
|
+
obj.each_header do |k, v|
|
100
|
+
hds[k] = v
|
101
|
+
end
|
102
|
+
|
103
|
+
hds
|
104
|
+
end
|
105
|
+
|
106
|
+
def keep_alive_interval
|
107
|
+
25
|
108
|
+
end
|
109
|
+
|
110
|
+
def hash_to_query(hash)
|
111
|
+
return URI.encode(hash.map { |k, v| "#{k}=#{v}" }.join("&"))
|
112
|
+
end
|
113
|
+
|
114
|
+
attr_reader :output, :loggregator_host, :user_token, :trace
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'cf'
|
2
|
+
|
3
|
+
module LogsCfPlugin
|
4
|
+
require 'logs-cf-plugin/loggregator_client'
|
5
|
+
require 'logs-cf-plugin/log_target'
|
6
|
+
require 'logs-cf-plugin/message_writer'
|
7
|
+
|
8
|
+
class Plugin < CF::CLI
|
9
|
+
include LoginRequirements
|
10
|
+
|
11
|
+
desc "Tail or dump logs for CF applications or spaces"
|
12
|
+
group :apps
|
13
|
+
input :app, :desc => "App to tail logs from", :argument => :optional, :from_given => by_name(:app)
|
14
|
+
input :space, :type => :boolean, :desc => "Logs of all apps in the current space", :default => false
|
15
|
+
input :org, :type => :boolean, :desc => "Logs of all apps and spaces in the current organization", :default => false
|
16
|
+
input :recent, :type => :boolean, :desc => "Dump recent logs instead of tailing", :default => false
|
17
|
+
|
18
|
+
def logs
|
19
|
+
guids = [client.current_organization.guid, client.current_space.guid, input[:app].try(:guid)]
|
20
|
+
|
21
|
+
log_target = LogTarget.new(input[:org], input[:space], guids)
|
22
|
+
|
23
|
+
if log_target.ambiguous?
|
24
|
+
Mothership::Help.command_help(@@commands[:logs])
|
25
|
+
fail "Please provide either --space or --org, but not both."
|
26
|
+
end
|
27
|
+
|
28
|
+
unless log_target.valid?
|
29
|
+
Mothership::Help.command_help(@@commands[:logs])
|
30
|
+
fail "Please provide an application to log."
|
31
|
+
end
|
32
|
+
|
33
|
+
loggregator_client = LoggregatorClient.new(loggregator_host, client.token.auth_header, STDOUT, input[:trace])
|
34
|
+
|
35
|
+
if input[:recent]
|
36
|
+
loggregator_client.dump_messages(log_target.query_params).each do |m|
|
37
|
+
MessageWriter.write(STDOUT, m)
|
38
|
+
end
|
39
|
+
|
40
|
+
else
|
41
|
+
loggregator_client.listen(log_target.query_params)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
::ManifestsPlugin.default_to_app_from_manifest(:logs, false)
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def loggregator_host
|
50
|
+
target_base = client.target.sub(/^https?:\/\/([^\.]+\.)?(.+)\/?/, '\2')
|
51
|
+
"loggregator.#{target_base}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
## Generated from log_message.proto for logMessage
|
2
|
+
require "beefcake"
|
3
|
+
|
4
|
+
|
5
|
+
class LogMessage
|
6
|
+
include Beefcake::Message
|
7
|
+
|
8
|
+
module MessageType
|
9
|
+
OUT = 1
|
10
|
+
ERR = 2
|
11
|
+
end
|
12
|
+
module SourceType
|
13
|
+
CLOUD_CONTROLLER = 1
|
14
|
+
ROUTER = 2
|
15
|
+
UAA = 3
|
16
|
+
DEA = 4
|
17
|
+
WARDEN_CONTAINER = 5
|
18
|
+
end
|
19
|
+
|
20
|
+
required :message, :bytes, 1
|
21
|
+
required :message_type, LogMessage::MessageType, 2
|
22
|
+
required :timestamp, :sint64, 3
|
23
|
+
required :app_id, :string, 4
|
24
|
+
required :source_type, LogMessage::SourceType, 5
|
25
|
+
optional :source_id, :string, 6
|
26
|
+
optional :space_id, :string, 7
|
27
|
+
required :organization_id, :string, 8
|
28
|
+
|
29
|
+
def message_type_name
|
30
|
+
{MessageType::OUT => 'STDOUT', MessageType::ERR => 'STDERR'}[message_type]
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
package logMessage;
|
2
|
+
|
3
|
+
message LogMessage {
|
4
|
+
enum MessageType {
|
5
|
+
OUT = 1;
|
6
|
+
ERR = 2;
|
7
|
+
}
|
8
|
+
|
9
|
+
enum SourceType {
|
10
|
+
CLOUD_CONTROLLER = 1;
|
11
|
+
ROUTER = 2;
|
12
|
+
UAA = 3;
|
13
|
+
DEA = 4;
|
14
|
+
WARDEN_CONTAINER = 5;
|
15
|
+
}
|
16
|
+
|
17
|
+
required bytes message = 1;
|
18
|
+
required MessageType message_type = 2;
|
19
|
+
required sint64 timestamp = 3;
|
20
|
+
required string app_id = 4;
|
21
|
+
required SourceType source_type = 5;
|
22
|
+
optional string source_id = 6;
|
23
|
+
optional string space_id = 7;
|
24
|
+
required string organization_id = 8;
|
25
|
+
}
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: logs-cf-plugin
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.23.pre
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pivotal
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-08-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: cf
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.2.5
|
20
|
+
- - <
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '5.0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 4.2.5
|
30
|
+
- - <
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5.0'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: faye-websocket
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ~>
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.6.1
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.6.1
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: beefcake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.3.7
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ~>
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 0.3.7
|
61
|
+
description: CF command line tool to retrieve recent and tail CF Application Logs
|
62
|
+
email:
|
63
|
+
- vcap-dev@googlegroups.com
|
64
|
+
executables: []
|
65
|
+
extensions: []
|
66
|
+
extra_rdoc_files: []
|
67
|
+
files:
|
68
|
+
- lib/logs-cf-plugin/log_target.rb
|
69
|
+
- lib/logs-cf-plugin/loggregator_client.rb
|
70
|
+
- lib/logs-cf-plugin/message_writer.rb
|
71
|
+
- lib/logs-cf-plugin/plugin.rb
|
72
|
+
- vendor/log_message/log_message.pb.rb
|
73
|
+
- vendor/log_message/log_message.proto
|
74
|
+
- README.md
|
75
|
+
homepage: http://github.com/cloudfoundry/logs-cf-plugin
|
76
|
+
licenses:
|
77
|
+
- Apache 2.0
|
78
|
+
metadata: {}
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
- vendor
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 1.9.3
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ! '>'
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.3.1
|
94
|
+
requirements: []
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 2.0.6
|
97
|
+
signing_key:
|
98
|
+
specification_version: 4
|
99
|
+
summary: CF Logs
|
100
|
+
test_files: []
|